From dd2b19116ccb037ecf0bc4ce4fe1c75a59408bfd Mon Sep 17 00:00:00 2001 From: Sheogorath <sheogorath@shivering-isles.com> Date: Sun, 8 Oct 2023 01:48:29 +0200 Subject: [PATCH] feat(nut-exporter): Add tests and serviceaccount This patch adjusts the helm chart to become more standardised. It uses helm unittest to valdiate changes as well as implementing a serviceaccount as best practice. It also goes back to all the default helm helpers for labels, names etc. --- charts/nut-exporter/Chart.yaml | 2 +- charts/nut-exporter/README.md | 5 +- charts/nut-exporter/templates/_helpers.tpl | 48 ++++- .../templates/configmap-dashboard.yaml | 2 +- charts/nut-exporter/templates/deployment.yaml | 1 + charts/nut-exporter/templates/podmonitor.yaml | 2 +- .../templates/prometheus-rules.yaml | 2 +- .../templates/serviceaccount.yaml | 12 ++ .../__snapshot__/snapshot_test.yaml.snap | 171 ++++++++++++++++++ .../nut-exporter/tests/helmlabels_test.yaml | 23 +++ charts/nut-exporter/tests/snapshot_test.yaml | 14 ++ charts/nut-exporter/values.yaml | 8 + 12 files changed, 277 insertions(+), 13 deletions(-) create mode 100644 charts/nut-exporter/templates/serviceaccount.yaml create mode 100644 charts/nut-exporter/tests/__snapshot__/snapshot_test.yaml.snap create mode 100644 charts/nut-exporter/tests/helmlabels_test.yaml create mode 100644 charts/nut-exporter/tests/snapshot_test.yaml diff --git a/charts/nut-exporter/Chart.yaml b/charts/nut-exporter/Chart.yaml index d729590c7..8fd807adc 100644 --- a/charts/nut-exporter/Chart.yaml +++ b/charts/nut-exporter/Chart.yaml @@ -13,5 +13,5 @@ sources: - https://github.com/acolombier/nut_exporter/tree/feat/add-helm-chart type: application -version: 0.1.0 +version: 0.2.0 appVersion: 3.0.0 diff --git a/charts/nut-exporter/README.md b/charts/nut-exporter/README.md index 92ae38f77..a2cbd879e 100644 --- a/charts/nut-exporter/README.md +++ b/charts/nut-exporter/README.md @@ -1,6 +1,6 @@ # nut-exporter -   +   Installs NUT exporter in Kubernetes @@ -34,6 +34,9 @@ Installs NUT exporter in Kubernetes | securityContext.allowPrivilegeEscalation | bool | `false` | | | securityContext.capabilities.drop[0] | string | `"ALL"` | | | securityContext.readOnlyRootFilesystem | bool | `true` | | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | | tolerations | list | `[]` | | ---------------------------------------------- diff --git a/charts/nut-exporter/templates/_helpers.tpl b/charts/nut-exporter/templates/_helpers.tpl index 484493f09..0cf5723f2 100644 --- a/charts/nut-exporter/templates/_helpers.tpl +++ b/charts/nut-exporter/templates/_helpers.tpl @@ -1,30 +1,62 @@ {{/* -Defining names +Expand the name of the chart. */}} {{- define "nutexporter.name" -}} -{{- .Release.Name }}-nut-exporter +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} {{- end }} -{{- define "nutexporter.fullName" -}} -{{- .Release.Namespace }}-{{ include "nutexporter.name" . }} +{{/* +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 "nutexporter.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 "nutexporter.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} {{/* Common labels */}} {{- define "nutexporter.labels" -}} +helm.sh/chart: {{ include "nutexporter.chart" . }} {{ include "nutexporter.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} -app.kubernetes.io/part-of: nut-exporter -version: {{ .Chart.Version }} {{- end }} {{/* Selector labels */}} {{- define "nutexporter.selectorLabels" -}} -app.kubernetes.io/component: server +app.kubernetes.io/name: {{ include "nutexporter.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} -app.kubernetes.io/name: nut-exporter +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "nutexporter.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "nutexporter.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} {{- end }} \ No newline at end of file diff --git a/charts/nut-exporter/templates/configmap-dashboard.yaml b/charts/nut-exporter/templates/configmap-dashboard.yaml index acbd2ceeb..ad7eb37d5 100644 --- a/charts/nut-exporter/templates/configmap-dashboard.yaml +++ b/charts/nut-exporter/templates/configmap-dashboard.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ include "nutexporter.name" . }}-dashboards + name: {{ include "nutexporter.fullname" . }}-dashboards labels: {{- include "nutexporter.labels" . | nindent 4 }} {{- toYaml .Values.dashboard.labels | nindent 4 }} diff --git a/charts/nut-exporter/templates/deployment.yaml b/charts/nut-exporter/templates/deployment.yaml index 3b455d6fd..0d90c56b5 100644 --- a/charts/nut-exporter/templates/deployment.yaml +++ b/charts/nut-exporter/templates/deployment.yaml @@ -16,6 +16,7 @@ spec: labels: {{- include "nutexporter.selectorLabels" . | nindent 8 }} spec: + serviceAccountName: {{ include "nutexporter.serviceAccountName" . }} containers: - name: nut-exporter image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" diff --git a/charts/nut-exporter/templates/podmonitor.yaml b/charts/nut-exporter/templates/podmonitor.yaml index 3255e5cdf..e6b7f2715 100644 --- a/charts/nut-exporter/templates/podmonitor.yaml +++ b/charts/nut-exporter/templates/podmonitor.yaml @@ -7,7 +7,7 @@ metadata: {{- with .Values.podMonitor.labels }} {{- toYaml . | nindent 4 }} {{- end }} - name: {{ include "nutexporter.name" . }} + name: {{ include "nutexporter.fullname" . }} spec: podMetricsEndpoints: - interval: 15s diff --git a/charts/nut-exporter/templates/prometheus-rules.yaml b/charts/nut-exporter/templates/prometheus-rules.yaml index c7dcfb783..104ba1eef 100644 --- a/charts/nut-exporter/templates/prometheus-rules.yaml +++ b/charts/nut-exporter/templates/prometheus-rules.yaml @@ -2,7 +2,7 @@ apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: - name: {{ include "nutexporter.name" . }}-rules + name: {{ include "nutexporter.fullname" . }}-rules labels: {{- include "nutexporter.labels" . | nindent 4 }} {{- with .Values.rules.labels }} diff --git a/charts/nut-exporter/templates/serviceaccount.yaml b/charts/nut-exporter/templates/serviceaccount.yaml new file mode 100644 index 000000000..6e2e2f244 --- /dev/null +++ b/charts/nut-exporter/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "nutexporter.serviceAccountName" . }} + labels: + {{- include "nutexporter.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/nut-exporter/tests/__snapshot__/snapshot_test.yaml.snap b/charts/nut-exporter/tests/__snapshot__/snapshot_test.yaml.snap new file mode 100644 index 000000000..041da4977 --- /dev/null +++ b/charts/nut-exporter/tests/__snapshot__/snapshot_test.yaml.snap @@ -0,0 +1,171 @@ +should match basic snapshot: + 1: | + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: nut-exporter + app.kubernetes.io/version: 4.5.6 + helm.sh/chart: nut-exporter-1.2.3 + name: nut-exporter + spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/name: nut-exporter + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/name: nut-exporter + spec: + containers: + - env: + - name: NUT_EXPORTER_SERVER + value: 192.0.2.1 + image: ghcr.io/druggeri/nut_exporter:4.5.6 + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 5 + httpGet: + path: /ups_metrics + port: http + initialDelaySeconds: 10 + timeoutSeconds: 2 + name: nut-exporter + ports: + - containerPort: 9199 + name: http + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /ups_metrics + port: http + initialDelaySeconds: 5 + timeoutSeconds: 2 + resources: + limits: + cpu: 200m + memory: 128Mi + requests: + cpu: 50m + memory: 24Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + securityContext: + runAsGroup: 3642 + runAsNonRoot: true + runAsUser: 3642 + seccompProfile: + type: RuntimeDefault + serviceAccountName: RELEASE-NAME-nut-exporter + 2: | + apiVersion: v1 + data: + nutdashboard.json: "" + kind: ConfigMap + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: nut-exporter + app.kubernetes.io/version: 4.5.6 + grafana_dashboard: "1" + helm.sh/chart: nut-exporter-1.2.3 + name: RELEASE-NAME-nut-exporter-dashboards + 3: | + apiVersion: monitoring.coreos.com/v1 + kind: PodMonitor + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: nut-exporter + app.kubernetes.io/version: 4.5.6 + helm.sh/chart: nut-exporter-1.2.3 + name: RELEASE-NAME-nut-exporter + spec: + jobLabel: nut-exporter + namespaceSelector: + matchNames: + - NAMESPACE + podMetricsEndpoints: + - interval: 15s + path: /ups_metrics + port: http + scheme: http + selector: + matchLabels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/name: nut-exporter + 4: | + apiVersion: monitoring.coreos.com/v1 + kind: PrometheusRule + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: nut-exporter + app.kubernetes.io/version: 4.5.6 + helm.sh/chart: nut-exporter-1.2.3 + name: RELEASE-NAME-nut-exporter-rules + spec: + groups: + - name: NutExporter + rules: + - alert: UPSBatteryNeedsReplacement + annotations: + message: '{{ $labels.ups }} is indicating a need for a battery replacement.' + expr: network_ups_tools_ups_status{flag="RB"} != 0 + for: 60s + labels: + severity: high + - alert: UPSLowBattery + annotations: + message: '{{ $labels.ups }} has low battery and is running on backup. Expect shutdown soon' + expr: network_ups_tools_ups_status{flag="LB"} == 0 and network_ups_tools_ups_status{flag="OL"} == 0 + for: 60s + labels: + severity: critical + - alert: UPSRuntimeShort + annotations: + message: '{{ $labels.ups }} has only {{ $value | humanizeDuration}} of battery autonomy' + expr: network_ups_tools_battery_runtime < 300 + for: 30s + labels: + severity: high + - alert: UPSMainPowerOutage + annotations: + message: '{{ $labels.ups }} has no main power and is running on backup.' + expr: network_ups_tools_ups_status{flag="OL"} == 0 + for: 60s + labels: + severity: critical + - alert: UPSIndicatesWarningStatus + annotations: + message: '{{ $labels.ups }} is indicating a need for a battery replacement.' + expr: network_ups_tools_ups_status{flag="HB"} != 0 + for: 60s + labels: + severity: warning + 5: | + apiVersion: v1 + kind: ServiceAccount + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: nut-exporter + app.kubernetes.io/version: 4.5.6 + helm.sh/chart: nut-exporter-1.2.3 + name: RELEASE-NAME-nut-exporter diff --git a/charts/nut-exporter/tests/helmlabels_test.yaml b/charts/nut-exporter/tests/helmlabels_test.yaml new file mode 100644 index 000000000..73dabab0f --- /dev/null +++ b/charts/nut-exporter/tests/helmlabels_test.yaml @@ -0,0 +1,23 @@ +suite: Kubernetes recommendations +templates: + - configmap-dashboard.yaml + - deployment.yaml + - podmonitor.yaml + - prometheus-rules.yaml + - serviceaccount.yaml +tests: + - it: should have the kubernetes recommended labels + release: + name: "test-suite" + chart: + version: 1.2.3 + asserts: + - equal: + path: metadata.labels["app.kubernetes.io/instance"] + value: "test-suite" + - equal: + path: metadata.labels["app.kubernetes.io/managed-by"] + value: "Helm" + - equal: + path: metadata.labels["app.kubernetes.io/name"] + value: "nut-exporter" diff --git a/charts/nut-exporter/tests/snapshot_test.yaml b/charts/nut-exporter/tests/snapshot_test.yaml new file mode 100644 index 000000000..4d1164a0d --- /dev/null +++ b/charts/nut-exporter/tests/snapshot_test.yaml @@ -0,0 +1,14 @@ +suite: NUT-exporter +templates: + - deployment.yaml + - configmap-dashboard.yaml + - podmonitor.yaml + - prometheus-rules.yaml + - serviceaccount.yaml +tests: + - it: should match basic snapshot + chart: + version: 1.2.3 + appVersion: 4.5.6 + asserts: + - matchSnapshot: {} \ No newline at end of file diff --git a/charts/nut-exporter/values.yaml b/charts/nut-exporter/values.yaml index 55d1cda0a..026074e9f 100644 --- a/charts/nut-exporter/values.yaml +++ b/charts/nut-exporter/values.yaml @@ -88,6 +88,14 @@ tolerations: [] # operator: "Exists" # effect: NoSchedule +serviceAccount: + # -- Specifies whether a service account should be created + create: true + # -- Annotations to add to the service account + annotations: {} + # -- The name of the service account to use. If not set and create is true, a name is generated using the fullname template + name: "" + # -- Prometheus rules to trigger alerts from UPS rules: enabled: true -- GitLab