Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci-pr-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ jobs:
chartName: shoot-grafter
- chartDir: oidc-discovery-access/charts/1.0.0/oidc-discovery-access
chartName: oidc-discovery-access
- chartDir: netapp-monitoring/charts
chartName: netapp-monitoring

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/helm-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ on:
- trust-manager/charts/**
- repo-guard/charts/**
- oidc-discovery-access/**
- netapp-monitoring/charts/**


permissions:
Expand Down Expand Up @@ -94,6 +95,8 @@ jobs:
chartName: repo-guard
- chartDir: oidc-discovery-access/charts/1.0.0/oidc-discovery-access
chartName: oidc-discovery-access
- chartDir: netapp-monitoring/charts
chartName: netapp-monitoring


steps:
Expand Down
1 change: 1 addition & 0 deletions kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ resources:
- teams2slack/plugindefinition.yaml
- thanos/plugindefinition.yaml
- trust-manager/plugindefinition.yaml
- netapp-monitoring/plugindefinition.yaml
147 changes: 147 additions & 0 deletions netapp-monitoring/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
title: NetApp Monitoring
---

Learn more about the **netapp-monitoring** plugin. Use it to deploy [Harvest](https://github.com/NetApp/harvest) for monitoring NetApp storage filers via Prometheus metrics.

## Overview

This plugin deploys a monitoring stack for NetApp storage systems using [NetApp Harvest](https://github.com/NetApp/harvest). Harvest collects performance, capacity, and health metrics from ONTAP systems and exposes them via a Prometheus exporter.

The chart includes a service discovery component ([netappsd](https://github.com/sapcc/netappsd/tree/dme-strg)) that automatically discovers NetApp filers from Netbox and spawns Harvest instances to collect metrics.

## Architecture

Components included in this plugin:

- **Harvest** — Collects metrics from NetApp ONTAP systems using REST/ZAPI collectors and exports them in Prometheus format.
- **NetApp SD (Service Discovery)** — Discovers filers from Netbox and manages Harvest worker instances dynamically.
- **Master** — Queries Netbox for filer inventory and coordinates workers.
- **Worker** — Runs Harvest instances for discovered filers and exposes metrics.

## Quick Start

**Prerequisites**

- A running and Greenhouse-onboarded Kubernetes cluster.
- NetApp ONTAP filer credentials.
- Netbox API access with a valid token.

**Step 1:**

Install the `netapp-monitoring` plugin via the Greenhouse dashboard or by creating a `Plugin` resource in your Greenhouse central cluster.

**Step 2:**

Configure the required options:

| Parameter | Description | Required |
Comment thread
viennaa marked this conversation as resolved.
|-----------|-------------|----------|
| `harvest.image.repository` | Harvest container image repository | Yes |
| `harvest.image.tag` | Harvest container image tag | Yes |
| `netappsd.enabled` | Enable NetApp service discovery | Yes |
| `netappsd.image.repository` | NetApp SD container image repository | Yes |
| `netappsd.image.tag` | NetApp SD container image tag | Yes |
| `netappsd.region` | Region for service discovery | Yes |
| `netappsd.lob` | Line of business label applied to discovered filer metrics | Yes |
| `netappsd.credentials_file` | Mount path for the Harvest credentials file inside the poller container | Yes |
| `netappsd.credentials_secret` | Name of the generated credentials secret (for example `local-basic-auth`) | Yes |
| `netappsd.netapp_exporter_user` | NetApp exporter username | Yes |
| `netappsd.netapp_exporter_password` | NetApp exporter password | Yes |
| `netappsd.netbox_api_token` | Netbox API token | Yes |
| `netappsd.netbox_host` | Netbox host URL | Yes |
| `apps` | Map of app labels to enable discovery (for example cinder/manila/apod/cinder-manila) | No |

## Configuration

### netappsd Controller Behavior and RBAC

The `netappsd` master component acts as a controller for discovered filers.

- It monitors filer inventory from Netbox and reconciles the desired worker state.
- It scales worker Deployments up and down based on filers discovered for each configured app label.
- It patches Pod metadata to update the `filer` label, which is used to associate running workers with the discovered filer identity.

For this reason, the chart grants the `netappsd` service account these permissions in its namespace:

- `get`, `list`, `update`, `patch` on Pods
- `get`, `list`, `update`, `patch` on Deployments
- `get`, `list` on Endpoints

Without `patch` and `update`, the master cannot reconcile runtime labels or scaling decisions correctly.

The Deployment selectors and pod labels also stay app-specific on purpose. In [harvest-netappsd-master-deployment.yaml](charts/templates/harvest-netappsd-master-deployment.yaml) and [harvest-netappsd-worker-deployment.yaml](charts/templates/harvest-netappsd-worker-deployment.yaml), the shared helper labels used elsewhere in the chart are the same for every app (`cinder`, `manila`, `apod`, `cinder-manila`), so using them as the Deployment selector would make all master and worker Deployments select across each other's pods and break isolation. The `name: {{ include "netapp-monitoring.fullname" . }}-{{ $appName }}-master` label remains inline because it uniquely identifies pods per app and keeps each Deployment scoped to its own workload.

### Harvest

The Harvest component is configured with the following default collectors:

- `Ems` — Event Management System
- `Rest` — REST API metrics
- `RestPerf` — REST performance counters
- `KeyPerf` — Key performance metrics
- `Unix` — Unix host metrics
- `Simple` — Simple counter metrics

Metrics are exposed on port `13000` via the Prometheus exporter.

### Service Discovery Apps

The `apps` section configures which filers are discovered based on their Netbox labels:

```yaml
apps:
cinder:
enabled: true
manila:
enabled: true
apod:
enabled: true
cinder-manila:
enabled: true
```

### Example Plugin Resource

```yaml
apiVersion: greenhouse.sap/v1alpha1
kind: Plugin
metadata:
name: netapp-monitoring
spec:
pluginDefinition: netapp-monitoring
clusterName: my-cluster
optionValues:
- name: harvest.image.repository
value: keppel.eu-de-1.cloud.sap/ccloud/harvest
- name: harvest.image.tag
value: "25.11.0-20251126205434"
- name: netappsd.enabled
value: true
- name: netappsd.image.repository
value: keppel.eu-de-1.cloud.sap/ccloud/netappsd
- name: netappsd.image.tag
value: dme-strg-20260617091551
- name: netappsd.region
value: eu-de-1
- name: netappsd.netapp_exporter_user
valueFrom:
secret:
name: netapp-monitoring-secrets
key: exporter-user
- name: netappsd.netapp_exporter_password
valueFrom:
secret:
name: netapp-monitoring-secrets
key: exporter-password
- name: netappsd.netbox_api_token
valueFrom:
secret:
name: netapp-monitoring-secrets
key: netbox-token
```

## Maintainers

- Ganesh Kugulakrishnan
- Chandrakanth Renduchintala
23 changes: 23 additions & 0 deletions netapp-monitoring/charts/.helmignore
Original file line number Diff line number Diff line change
@@ -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/
6 changes: 6 additions & 0 deletions netapp-monitoring/charts/Chart.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dependencies:
- name: owner-info
repository: oci://keppel.eu-de-1.cloud.sap/ccloud-helm
version: 1.0.0
digest: sha256:45a74346d8c73d1b61264fa06d5cb48d3dc38abcfbaa2900b0b918fb532b52ba
generated: "2026-06-04T10:28:40.511395675-06:00"
18 changes: 18 additions & 0 deletions netapp-monitoring/charts/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors
# SPDX-License-Identifier: Apache-2.0

apiVersion: v2
name: netapp-monitoring
description: A Helm chart for harvest.io - https://github.com/NetApp/harvest
type: application
version: 1.0.0

# * Release tag of Harvest - https://github.com/NetApp/harvest/releases
appVersion: "25.11.0"
maintainers:
- name: Ganesh Kugulakrishnan
- name: Chandrakanth Renduchintala
dependencies:
- name: owner-info
repository: oci://keppel.eu-de-1.cloud.sap/ccloud-helm
version: 1.0.0
Binary file not shown.
105 changes: 105 additions & 0 deletions netapp-monitoring/charts/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
{{/*
# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors
# SPDX-License-Identifier: Apache-2.0
*/}}
{{/*
Expand the name of the chart.
*/}}
{{- define "netapp-monitoring.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 "netapp-monitoring.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 "netapp-monitoring.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "netapp-monitoring.labels" -}}
helm.sh/chart: {{ include "netapp-monitoring.chart" . }}
{{ include "netapp-monitoring.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "netapp-monitoring.selectorLabels" -}}
app.kubernetes.io/name: {{ include "netapp-monitoring.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "netapp-monitoring.serviceAccountName" -}}
{{- default "netappsd" .Values.netappsd.serviceAccountName }}
{{- end }}


{{/*
Create harvest basic auth credential entry based on credentials_secret.
*/}}

{{- define "netapp-monitoring.defaultCredentialsYaml" -}}
Defaults:
username: {{ printf "{{ resolve \"%s/username\" }}" .SecretPath }}
password: {{ printf "{{ resolve \"%s/password\" }}" .SecretPath }}
{{- end }}


{{- define "netapp-monitoring.credentials-entry" -}}
{{- if eq .Values.netappsd.credentials_secret "local-basic-auth" -}}
{{ include "netapp-monitoring.defaultCredentialsYaml" (dict "SecretPath" "vault+kvv2:///secrets/shared/harvest/harvest-ad/local-user") }}
{{- else if eq .Values.netappsd.credentials_secret "sci-basic-auth" -}}
{{ include "netapp-monitoring.defaultCredentialsYaml" (dict "SecretPath" "vault+kvv2:///secrets/shared/harvest/harvest-ad/sci-user") }}
{{- else if eq .Values.netappsd.credentials_secret "hec-basic-auth" -}}
{{ include "netapp-monitoring.defaultCredentialsYaml" (dict "SecretPath" "vault+kvv2:///secrets/shared/harvest/harvest-ad/hec-user") }}
{{- else if eq .Values.netappsd.credentials_secret "internal-basic-auth" -}}
{{ include "netapp-monitoring.defaultCredentialsYaml" (dict "SecretPath" "vault+kvv2:///secrets/shared/harvest/harvest-ad/internal-user") }}
{{- else -}}
{{- fail (printf "unsupported .Values.netappsd.credentials_secret: %q — must be one of local-basic-auth, sci-basic-auth, hec-basic-auth, internal-basic-auth" .Values.netappsd.credentials_secret) }}
{{- end }}
{{- end }}

{{/*
Checksum helpers used as pod-template annotations to force rolling updates
when config or secret templates change.
*/}}
{{- define "netapp-monitoring.checksum.configmap" -}}
{{ include (print $.Template.BasePath "/harvest-netappsd-configmap.yaml") . | sha256sum }}
{{- end }}

{{- define "netapp-monitoring.checksum.sdSecret" -}}
{{ include (print $.Template.BasePath "/harvest-netappsd-secret.yaml") . | sha256sum }}
{{- end }}

{{- define "netapp-monitoring.checksum.basicAuthSecret" -}}
{{ include (print $.Template.BasePath "/harvest-basic-auth.yaml") . | sha256sum }}
{{- end }}

19 changes: 19 additions & 0 deletions netapp-monitoring/charts/templates/harvest-basic-auth.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors
# SPDX-License-Identifier: Apache-2.0

{{- if .Values.netappsd.enabled }}
apiVersion: v1
kind: Secret
metadata:
finalizers:
{{- range $.Values.finalizers }}
- {{ . | quote }}
{{- end }}
name: {{ required ".Values.netappsd.credentials_secret is required" .Values.netappsd.credentials_secret }}
labels:
{{- include "netapp-monitoring.labels" . | nindent 4 }}
namespace: {{ .Release.Namespace }}
type: Opaque
data:
{{ required ".Values.netappsd.credentials_secret is required" .Values.netappsd.credentials_secret }}.yml: {{ include "netapp-monitoring.credentials-entry" . | b64enc }}
{{- end }}
Loading
Loading