From 3b4a5508c1bbca4729487b8e95fffaa6791c5f45 Mon Sep 17 00:00:00 2001
From: Nacho Barrientos <nacho.barrientos@cern.ch>
Date: Tue, 25 Feb 2025 10:47:27 +0100
Subject: [PATCH 1/4] [MONIT-4147] Make tenant credentials mandatory
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

With this patch the chart will fail to install if either tenant.name
or tenant.password are not set if they're necessary, example:

```
λ helm -n monitoring diff upgrade kubernetes-monitoring . -f values.yaml -f ibarrien.yaml
Error: Failed to render chart: exit status 1: Error: execution error at (cern-it-monitoring-kubernetes/templates/fluentbit-metrics/configmap.yaml:22:13): Tenand password is required
```

If no fluentbit forwarding is configured, i.e.:

```yaml
metrics:
  fluentbit:
    enabled: false

logs:
  fluentbit:
    enabled: false
```

then the chart installs fine as they're note required in that case.
---
 docs/values.md |  4 ++--
 values.yaml    | 16 ++++++++--------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/docs/values.md b/docs/values.md
index 4d3d066..a8aea77 100644
--- a/docs/values.md
+++ b/docs/values.md
@@ -81,8 +81,8 @@ This file contains the markdown version of the default values that this chart ta
 | metrics.alertmanager.nodeSelector | Hash | `{}` | node selector configuration for the alertmanager |
 | otlp.endpoint | string | `"monit-otlp.cern.ch"` | otlp endpoint where the otlp receivers are listening |
 | otlp.port | int | `4319` | otlp port where the otlp receivers are listening |
-| tenant.name | string | `"nil"` | username used for authenitcating in the MONIT infrastructure |
-| tenant.password | string | `"nil"` | password (plain) used for authenitcating in the MONIT infrastructure |
+| tenant.name | string | - | username used for authenitcating in the MONIT infrastructure |
+| tenant.password | string | - | password (plain) used for authenitcating in the MONIT infrastructure |
 | crds.enabled | bool | `true` | whether to install Prometheus operator's CRDs |
 
 ----------------------------------------------
diff --git a/values.yaml b/values.yaml
index a755779..7c6e0c8 100644
--- a/values.yaml
+++ b/values.yaml
@@ -10,12 +10,12 @@ otlp:
   port: 4319
 
 # Tenant configuration. Username and Password are provided via CERN Central IT
-# Monitoring service.
-tenant:
+# Monitoring service. This bit is required if fluentbit is enabled (default)
+# tenant:
   # -- username used for authenitcating in the MONIT infrastructure
-  name: nil
+  # name: example
   # -- password (plain) used for authenitcating in the MONIT infrastructure
-  password: nil
+  # password: example
 
 # Kubernetes configuration.
 kubernetes:
@@ -220,8 +220,8 @@ metrics:
         traces_uri: /v1/traces
         tls: on
         tls.verify: off
-        http_user: {{ .Values.tenant.name }}
-        http_passwd: {{ .Values.tenant.password }}
+        http_user: {{ required "Tenant name is required" (.Values.tenant).name }}
+        http_passwd: {{ required "Tenant password is required" (.Values.tenant).password }}
         storage.total_limit_size: {{ .Values.metrics.fluentbit.diskMaxCache }}
         header: User-Agent {{ .Chart.Name }}/{{ .Chart.Version }}
 
@@ -414,8 +414,8 @@ logs:
           traces_uri /v1/traces
           tls on
           tls.verify off
-          http_user {{ .Values.tenant.name }}
-          http_passwd {{ .Values.tenant.password }}
+          http_user {{ required "Tenant name is required" (.Values.tenant).name }}
+          http_passwd {{ required "Tenant password is required" (.Values.tenant).password }}
           header tag monit
           header log_type kubernetes
           header User-Agent {{ .Chart.Name }}/{{ .Chart.Version }}
-- 
GitLab


From aa3a8da1f3fa7c8d842644dfc7711830ab32a7e1 Mon Sep 17 00:00:00 2001
From: Nacho Barrientos <nacho.barrientos@cern.ch>
Date: Tue, 25 Feb 2025 10:55:25 +0100
Subject: [PATCH 2/4] [MONIT-4147] Correct variable reference

Moreover, if Prometheus remote write is enabled and
`metrics.prometheus.server.remoteWrite.username` and
`metrics.prometheus.server.remoteWrite.password` are not set the chart
will fail to install now.
---
 templates/prometheus/remotewritesecret.yaml | 4 ++--
 values.yaml                                 | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/templates/prometheus/remotewritesecret.yaml b/templates/prometheus/remotewritesecret.yaml
index 2c973aa..59eca9b 100644
--- a/templates/prometheus/remotewritesecret.yaml
+++ b/templates/prometheus/remotewritesecret.yaml
@@ -11,8 +11,8 @@ data:
   username: {{ .Values.metrics.prometheus.server.remoteWrite.username | b64enc }}
   password: {{ .Values.metrics.prometheus.server.remoteWrite.password | b64enc }}
 {{- else }}
-  username: {{ .Values.tenantName | b64enc }}
-  password: {{ .Values.tenantPassword | b64enc }}
+  username: {{ required "Tenant name is required" (.Values.tenant).name | b64enc }}
+  password: {{ required "Tenant password is required" (.Values.tenant).password | b64enc }}
 {{- end }}
 {{ end }}
 {{- end -}}
diff --git a/values.yaml b/values.yaml
index 7c6e0c8..c61e498 100644
--- a/values.yaml
+++ b/values.yaml
@@ -101,7 +101,7 @@ metrics:
       remoteWrite: {}
         # endpoint: "https://monit-prom-mom.cern.ch:9090/api/v1/write"
         # username: "your user" # If user and password are not provided then
-        #           tenantName and tenantPassword will be used.
+        #           tenant.name and tenant.password will be used.
         # password: "your password"
       resources:
         requests:
-- 
GitLab


From 11c444bddc169280d149b35a8dceb7ab040dcc2b Mon Sep 17 00:00:00 2001
From: Nacho Barrientos <nacho.barrientos@cern.ch>
Date: Tue, 25 Feb 2025 11:26:14 +0100
Subject: [PATCH 3/4] [MONIT-4147] Force kubernetes.clusterName when necessary

This patch forces Helm to abort if kubernetes.clusterName is not set
when *.fluentbit.enabled = true.
---
 docs/values.md                       | 2 +-
 templates/prometheus/prometheus.yaml | 4 +++-
 values.yaml                          | 8 ++++----
 3 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/docs/values.md b/docs/values.md
index a8aea77..5d9ac77 100644
--- a/docs/values.md
+++ b/docs/values.md
@@ -3,7 +3,7 @@ This file contains the markdown version of the default values that this chart ta
 
 | Key | Type | Default | Description |
 |-----|------|---------|-------------|
-| kubernetes.clusterName | string | `"nil"` | name of the kubernetes cluster to monitor. This value will be appended tovery metric and log via k8s_cluster_name label |
+| kubernetes.clusterName | string | - | name of the kubernetes cluster to monitor. This value will be appended tovery metric and log via k8s_cluster_name label |
 | logs.enabled | bool | `false` | indicates if logs components should be enabled or not. If set to false no logs component will be installed nor configured |
 | logs.fluentbit.customParsers | string | `""` |  |
 | logs.fluentbit.enabled | bool | `false` | indicates if fluentbit logs component should be installed or not |
diff --git a/templates/prometheus/prometheus.yaml b/templates/prometheus/prometheus.yaml
index 24f1056..b53ca4e 100644
--- a/templates/prometheus/prometheus.yaml
+++ b/templates/prometheus/prometheus.yaml
@@ -11,7 +11,9 @@ spec:
   scrapeTimeout: {{ .Values.metrics.prometheus.server.scrapeTimeout }}
   retention: {{ .Values.metrics.prometheus.server.retention }}
   externalLabels:
-    k8s_cluster_name: {{ .Values.kubernetes.clusterName }}
+    {{- if and .Values.metrics.fluentbit.enabled }}
+    k8s_cluster_name: {{ required "kubernetes.clusterName is missing" (.Values.kubernetes).clusterName -}}
+    {{- end -}}
     {{- with .Values.metrics.prometheus.server.extraLabelsForMetrics }}
     {{- toYaml . | nindent 4 }}
     {{- end }}
diff --git a/values.yaml b/values.yaml
index c61e498..d9f8842 100644
--- a/values.yaml
+++ b/values.yaml
@@ -18,9 +18,9 @@ otlp:
   # password: example
 
 # Kubernetes configuration.
-kubernetes:
-  # -- name of the kubernetes cluster to monitor. This value will be appended to very metric and log via k8sClusterName label
-  clusterName: nil
+# kubernetes:
+  # -- name of the kubernetes cluster to monitor. This value will be appended to very metric and log via k8sClusterName label. This bit is required if fluentbit is enabled (default)
+  # clusterName: nil
 
 # The metrics section includes all the components meant to produce, scrape,
 # collect or forward metrics. You can configure all components independently.
@@ -381,7 +381,7 @@ logs:
       [FILTER]
           Name modify
           Match *
-          Add kubernetes_cluster_name {{ .Values.kubernetes.clusterName }}
+          Add kubernetes_cluster_name {{ required "kubernetes.clusterName is missing" (.Values.kubernetes).clusterName }}
           Add monit_type kubernetes
           Remove kubernetes_container_hash
           Remove kubernetes_docker_id
-- 
GitLab


From 51cf27a38e6215f0c586aa4e091c9a3749f05246 Mon Sep 17 00:00:00 2001
From: Nacho Barrientos <nacho.barrientos@cern.ch>
Date: Mon, 3 Mar 2025 15:24:19 +0100
Subject: [PATCH 4/4] [MONIT-4147] Add some unit tests

---
 .gitlab-ci.yml                           |  6 ++
 .helmignore                              |  3 +-
 tests/fluentbit-logs/configmap.yaml      | 51 ++++++++++++++++
 tests/fluentbit-logs/daemonset.yaml      | 38 ++++++++++++
 tests/fluentbit-metrics/configmap.yaml   | 35 +++++++++++
 tests/fluentbit-metrics/statefulset.yaml | 29 +++++++++
 tests/prometheus/prometheus.yaml         | 75 ++++++++++++++++++++++++
 tests/prometheus/remotewritesecret.yaml  | 36 ++++++++++++
 8 files changed, 272 insertions(+), 1 deletion(-)
 create mode 100644 tests/fluentbit-logs/configmap.yaml
 create mode 100644 tests/fluentbit-logs/daemonset.yaml
 create mode 100644 tests/fluentbit-metrics/configmap.yaml
 create mode 100644 tests/fluentbit-metrics/statefulset.yaml
 create mode 100644 tests/prometheus/prometheus.yaml
 create mode 100644 tests/prometheus/remotewritesecret.yaml

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5d1c07a..6ebd77d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -42,6 +42,12 @@ helm_lint:
     - helm dep update .
     - helm lint --strict .
 
+unittest:
+  stage: test
+  image: registry.cern.ch/docker.io/helmunittest/helm-unittest:3.17.0-0.7.2
+  script:
+    - helm unittest -f 'tests/**/*.yaml' .
+
 version_test:
   stage: test
   rules:
diff --git a/.helmignore b/.helmignore
index df65d10..f72da33 100644
--- a/.helmignore
+++ b/.helmignore
@@ -27,4 +27,5 @@ README.md
 .idea/
 *.tmproj
 .vscode/
-config
\ No newline at end of file
+config
+tests/
\ No newline at end of file
diff --git a/tests/fluentbit-logs/configmap.yaml b/tests/fluentbit-logs/configmap.yaml
new file mode 100644
index 0000000..1627cb7
--- /dev/null
+++ b/tests/fluentbit-logs/configmap.yaml
@@ -0,0 +1,51 @@
+suite: test fluentbit-logs configmap
+templates:
+  - fluentbit-logs/configmap.yaml
+tests:
+  - it: should deploy nothing by default
+    asserts:
+      - containsDocument:
+          kind: ConfigMap
+          apiVersion: "apps/v1"
+          name: it-monit-logs-collector-fluentbit
+        not: true
+  - it: should fail to deploy if enabled due to missing cluster name
+    set:
+      logs.enabled: true
+      logs.fluentbit.enabled: true
+    asserts:
+      - failedTemplate:
+          errorMessage: "kubernetes.clusterName is missing"
+  - it: should fail to deploy if enabled due to missing tenant details
+    set:
+      logs.enabled: true
+      logs.fluentbit.enabled: true
+      kubernetes.clusterName: test
+    asserts:
+      - failedTemplate:
+          errorMessage: "Tenant name is required"
+  - it: should fail to deploy if enabled when tenant name available but no tenant password
+    set:
+      logs.enabled: true
+      logs.fluentbit.enabled: true
+      tenant.name: test
+      kubernetes.clusterName: test
+    asserts:
+      - failedTemplate:
+          errorMessage: "Tenant password is required"
+  - it: should deploy if logs processing is enabled and required values are fed
+    set:
+      tenant.name: test
+      tenant.password: test
+      kubernetes.clusterName: test
+      logs.enabled: true
+      logs.fluentbit.enabled: true
+    asserts:
+      - containsDocument:
+          kind: ConfigMap
+          apiVersion: v1
+          name: it-monit-logs-collector-fluentbit
+      - exists:
+          path: data["custom_parsers.conf"]
+      - exists:
+          path: data["fluent-bit.conf"]
diff --git a/tests/fluentbit-logs/daemonset.yaml b/tests/fluentbit-logs/daemonset.yaml
new file mode 100644
index 0000000..4669c91
--- /dev/null
+++ b/tests/fluentbit-logs/daemonset.yaml
@@ -0,0 +1,38 @@
+suite: test fluentbit-logs daemonset
+templates:
+  - fluentbit-logs/daemonset.yaml
+tests:
+  - it: should not be deployed by default
+    asserts:
+      - containsDocument:
+          kind: DaemonSet
+          apiVersion: "apps/v1"
+          name: it-monit-logs-collector-fluentbit
+        not: true
+  - it: should be deployed if logs.enabled and logs.fluentbit.enabled is true
+    set:
+      logs.enabled: true
+      logs.fluentbit.enabled: true
+    asserts:
+      - containsDocument:
+          kind: DaemonSet
+          apiVersion: "apps/v1"
+          name: it-monit-logs-collector-fluentbit
+  - it: should not be deployed if logs.enabled is false
+    set:
+      logs.enabled: false
+    asserts:
+      - containsDocument:
+          kind: DaemonSet
+          apiVersion: "apps/v1"
+        not: true
+  - it: should not be deployed if logs.enabled is true and logs.fluentbit.enabled is false
+    set:
+      logs.enabled: true
+      logs.fluentbit.enabled: false
+    asserts:
+      - containsDocument:
+          kind: DaemonSet
+          apiVersion: "apps/v1"
+          name: it-monit-logs-collector-fluentbit
+        not: true
diff --git a/tests/fluentbit-metrics/configmap.yaml b/tests/fluentbit-metrics/configmap.yaml
new file mode 100644
index 0000000..82e9a84
--- /dev/null
+++ b/tests/fluentbit-metrics/configmap.yaml
@@ -0,0 +1,35 @@
+suite: test fluentbit-metrics configmap
+templates:
+  - fluentbit-metrics/configmap.yaml
+tests:
+  - it: should fail to deploy by default due to missing tenant details
+    asserts:
+      - failedTemplate:
+          errorMessage: "Tenant name is required"
+  - it: should fail to deploy if tenant name available but no tenant password
+    set:
+      tenant.name: test
+    asserts:
+      - failedTemplate:
+          errorMessage: "Tenant password is required"
+  - it: should deploy by default when required values are fed
+    set:
+      tenant.name: test
+      tenant.password: test
+    asserts:
+      - containsDocument:
+          kind: ConfigMap
+          apiVersion: v1
+  - it: should deploy if metrics processing is enabled and required values are fed
+    set:
+      tenant.name: test
+      tenant.password: test
+      metrics.enabled: true
+      metrics.fluentbit.enabled: true
+    asserts:
+      - containsDocument:
+          kind: ConfigMap
+          apiVersion: v1
+          name: it-monit-metrics-collector-fluentbit
+      - exists:
+          path: data["fluent-bit.yaml"]
diff --git a/tests/fluentbit-metrics/statefulset.yaml b/tests/fluentbit-metrics/statefulset.yaml
new file mode 100644
index 0000000..56f19e0
--- /dev/null
+++ b/tests/fluentbit-metrics/statefulset.yaml
@@ -0,0 +1,29 @@
+suite: test fluentbit-metrics statefulset
+templates:
+  - fluentbit-metrics/statefulset.yaml
+tests:
+  - it: should be deployed by default
+    asserts:
+      - containsDocument:
+          kind: StatefulSet
+          apiVersion: "apps/v1"
+          name: it-monit-metrics-collector-fluentbit
+  - it: should not be deployed if metrics.enabled is false
+    set:
+      metrics.enabled: false
+    asserts:
+      - containsDocument:
+          kind: StatefulSet
+          apiVersion: "apps/v1"
+          name: it-monit-metrics-collector-fluentbit
+        not: true
+  - it: should not be deployed if metrics.enabled is true and metrics.fluentbit.enabled is false
+    set:
+      metrics.enabled: true
+      metrics.fluentbit.enabled: false
+    asserts:
+      - containsDocument:
+          kind: StatefulSet
+          apiVersion: "apps/v1"
+          name: it-monit-metrics-collector-fluentbit
+        not: true
diff --git a/tests/prometheus/prometheus.yaml b/tests/prometheus/prometheus.yaml
new file mode 100644
index 0000000..a019b61
--- /dev/null
+++ b/tests/prometheus/prometheus.yaml
@@ -0,0 +1,75 @@
+suite: test prometheus prometheus
+templates:
+  - prometheus/prometheus.yaml
+tests:
+  - it: should not be deployed if metrics are disabled
+    set:
+      metrics.enabled: false
+    asserts:
+      - containsDocument:
+          kind: Prometheus
+          apiVersion: "monitoring.coreos.com/v1"
+          name: it-monit-metrics-collector-prometheus
+        not: true
+  - it: should not be deployed if Prometheus is disabled
+    set:
+      metrics.enabled: true
+      metrics.prometheus.enabled: false
+    asserts:
+      - containsDocument:
+          kind: Prometheus
+          apiVersion: "monitoring.coreos.com/v1"
+          name: it-monit-metrics-collector-prometheus
+        not: true
+  - it: should be deployed with cluster-local remote write by default
+    set:
+      kubernetes.clusterName: test
+    asserts:
+      - containsDocument:
+          kind: Prometheus
+          apiVersion: "monitoring.coreos.com/v1"
+          name: it-monit-metrics-collector-prometheus
+      - lengthEqual:
+          path: spec.remoteWrite
+          count: 1
+      - equal:
+          path: spec.remoteWrite[0].url
+          value: "http://it-monit-metrics-fluentbit:8080/api/prom/push"
+  - it: should be deployed with no remoteWrites if no fluentbit is available
+    set:
+      kubernetes.clusterName: test
+      metrics.fluentbit.enabled: false
+    asserts:
+      - containsDocument:
+          kind: Prometheus
+          apiVersion: "monitoring.coreos.com/v1"
+          name: it-monit-metrics-collector-prometheus
+      - lengthEqual:
+          path: spec.remoteWrite
+          count: 0
+  - it: should be deployed with external remote write if configured
+    set:
+      kubernetes.clusterName: test
+      metrics.fluentbit.enabled: false
+      metrics.prometheus.server.remoteWrite.endpoint: "http://foo:123"
+    asserts:
+      - containsDocument:
+          kind: Prometheus
+          apiVersion: "monitoring.coreos.com/v1"
+          name: it-monit-metrics-collector-prometheus
+      - contains:
+          path: spec.remoteWrite
+          content:
+            url: "http://foo:123"
+            tlsConfig:
+              insecureSkipVerify: true
+            basicAuth:
+              username:
+                name: it-monit-metrics-collector-prometheus
+                key: username
+              password:
+                name: it-monit-metrics-collector-prometheus
+                key: password
+      - lengthEqual:
+          path: spec.remoteWrite
+          count: 1
diff --git a/tests/prometheus/remotewritesecret.yaml b/tests/prometheus/remotewritesecret.yaml
new file mode 100644
index 0000000..1db96d7
--- /dev/null
+++ b/tests/prometheus/remotewritesecret.yaml
@@ -0,0 +1,36 @@
+suite: test prometheus remotewritesecret
+templates:
+  - prometheus/remotewritesecret.yaml
+tests:
+  - it: should be deployed with remote write specific creds if they're provided
+    set:
+      kubernetes.clusterName: test
+      tenant.name: test
+      tenant.password: tset
+      metrics.prometheus.server.remoteWrite.endpoint: "http://foo:123"
+      metrics.prometheus.server.remoteWrite.username: higgs
+      metrics.prometheus.server.remoteWrite.password: boson
+    asserts:
+      - containsDocument:
+          kind: Secret
+          apiVersion: "v1"
+      - equal:
+          path: data
+          value:
+            username: "aGlnZ3M=" # higgs
+            password: "Ym9zb24=" # boson
+  - it: should be deployed with tenant creds as user/password if provided
+    set:
+      kubernetes.clusterName: test
+      tenant.name: test
+      tenant.password: tset
+      metrics.prometheus.server.remoteWrite.endpoint: "http://foo:123"
+    asserts:
+      - containsDocument:
+          kind: Secret
+          apiVersion: "v1"
+      - equal:
+          path: data
+          value:
+            username: "dGVzdA==" # test
+            password: "dHNldA==" # tset
-- 
GitLab