From ad95a15a06eeb66c683b3e128f32f7accf40bc40 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Thu, 30 Jul 2026 17:14:09 +0300 Subject: [PATCH] fix(foundationdb): don't gate WorkloadMonitor behind monitoring.enabled WorkloadMonitor is a billing/metering meta-resource, not a tenant convenience feature: hiding it behind monitoring.enabled let a tenant turn off their own metering by flipping a values toggle. Every other app in the catalog ships its WorkloadMonitor unconditionally; drop the gate here so foundationdb matches. monitoring.enabled still gates dashboard-resourcemap.yaml (a dashboard/UI resource list, not a metering one), so the value stays. Assisted-By: Claude Signed-off-by: Timofei Larkin --- api/apps/v1alpha1/foundationdb/types.go | 2 +- packages/apps/foundationdb/Makefile | 6 ++- packages/apps/foundationdb/README.md | 9 +--- .../templates/workloadmonitor.yaml | 4 +- .../tests/workloadmonitor_test.yaml | 45 +++++++++++++++++++ packages/apps/foundationdb/values.schema.json | 2 +- packages/apps/foundationdb/values.yaml | 2 +- .../foundationdb-rd/cozyrds/foundationdb.yaml | 2 +- 8 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 packages/apps/foundationdb/tests/workloadmonitor_test.yaml diff --git a/api/apps/v1alpha1/foundationdb/types.go b/api/apps/v1alpha1/foundationdb/types.go index fa801afbf..faf28e675 100644 --- a/api/apps/v1alpha1/foundationdb/types.go +++ b/api/apps/v1alpha1/foundationdb/types.go @@ -125,7 +125,7 @@ type ClusterProcessCounts struct { } type Monitoring struct { - // Enable WorkloadMonitor integration. + // Enable the dashboard resource map used by the tenant UI. // +kubebuilder:default:=true Enabled bool `json:"enabled"` } diff --git a/packages/apps/foundationdb/Makefile b/packages/apps/foundationdb/Makefile index 60f9c50c4..7e693d795 100644 --- a/packages/apps/foundationdb/Makefile +++ b/packages/apps/foundationdb/Makefile @@ -2,4 +2,8 @@ include ../../../hack/package.mk generate: cozyvalues-gen -m 'foundationdb' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/foundationdb/types.go - ../../../hack/update-crd.sh \ No newline at end of file + ../../../hack/update-crd.sh + +.PHONY: test +test: + helm unittest . diff --git a/packages/apps/foundationdb/README.md b/packages/apps/foundationdb/README.md index c253bc67e..e3651a58f 100644 --- a/packages/apps/foundationdb/README.md +++ b/packages/apps/foundationdb/README.md @@ -107,12 +107,7 @@ securityContext: ## Monitoring -This package includes WorkloadMonitor integration for cluster health monitoring and resource tracking. Monitoring can be disabled by setting: - -```yaml -monitoring: - enabled: false -``` +This package includes WorkloadMonitor integration for cluster health monitoring and resource tracking. The WorkloadMonitor is always created and cannot be disabled, since it is also the resource used to meter and bill the workload. The `monitoring.enabled` flag only controls the dashboard resource map consumed by the tenant UI. ## Security @@ -186,7 +181,7 @@ For Cozystack-specific issues, consult the Cozystack documentation or support ch | `backup.s3.credentials.secretAccessKey` | DEPRECATED S3 secret access key. | `string` | `""` | | `backup.retentionPolicy` | DEPRECATED Retention policy for backups. | `string` | `7d` | | `monitoring` | Monitoring configuration. | `object` | `{}` | -| `monitoring.enabled` | Enable WorkloadMonitor integration. | `bool` | `true` | +| `monitoring.enabled` | Enable the dashboard resource map used by the tenant UI. | `bool` | `true` | ### FoundationDB configuration diff --git a/packages/apps/foundationdb/templates/workloadmonitor.yaml b/packages/apps/foundationdb/templates/workloadmonitor.yaml index 2e2a3d194..096772541 100644 --- a/packages/apps/foundationdb/templates/workloadmonitor.yaml +++ b/packages/apps/foundationdb/templates/workloadmonitor.yaml @@ -1,4 +1,3 @@ -{{- if .Values.monitoring.enabled }} --- apiVersion: cozystack.io/v1alpha1 kind: WorkloadMonitor @@ -17,5 +16,4 @@ spec: selector: foundationdb.org/fdb-cluster-name: {{ .Release.Name }} foundationdb.org/fdb-process-class: storage - version: {{ .Chart.Version }} -{{- end }} \ No newline at end of file + version: {{ .Chart.Version }} \ No newline at end of file diff --git a/packages/apps/foundationdb/tests/workloadmonitor_test.yaml b/packages/apps/foundationdb/tests/workloadmonitor_test.yaml new file mode 100644 index 000000000..843232a7f --- /dev/null +++ b/packages/apps/foundationdb/tests/workloadmonitor_test.yaml @@ -0,0 +1,45 @@ +suite: FoundationDB WorkloadMonitor renders unconditionally + +# WorkloadMonitor is the billing/metering meta-resource for this workload. +# It must never be gated behind the tenant-facing monitoring.enabled flag — +# that would let a tenant disable their own metering. + +templates: + - templates/workloadmonitor.yaml + +set: + _cluster: + cluster-domain: cluster.local + +tests: + - it: renders when monitoring.enabled is true + release: + name: test-fdb + namespace: tenant-test + set: + monitoring: + enabled: true + asserts: + - hasDocuments: + count: 1 + - isKind: + of: WorkloadMonitor + - equal: + path: metadata.name + value: test-fdb + + - it: still renders when monitoring.enabled is false + release: + name: test-fdb + namespace: tenant-test + set: + monitoring: + enabled: false + asserts: + - hasDocuments: + count: 1 + - isKind: + of: WorkloadMonitor + - equal: + path: metadata.name + value: test-fdb diff --git a/packages/apps/foundationdb/values.schema.json b/packages/apps/foundationdb/values.schema.json index 4c22a1d32..f108f7e27 100644 --- a/packages/apps/foundationdb/values.schema.json +++ b/packages/apps/foundationdb/values.schema.json @@ -285,7 +285,7 @@ ], "properties": { "enabled": { - "description": "Enable WorkloadMonitor integration.", + "description": "Enable the dashboard resource map used by the tenant UI.", "type": "boolean", "default": true } diff --git a/packages/apps/foundationdb/values.yaml b/packages/apps/foundationdb/values.yaml index b9ea43106..830efd306 100644 --- a/packages/apps/foundationdb/values.yaml +++ b/packages/apps/foundationdb/values.yaml @@ -131,7 +131,7 @@ backup: retentionPolicy: "7d" ## @typedef {struct} Monitoring - Monitoring configuration. -## @field {bool} enabled - Enable WorkloadMonitor integration. +## @field {bool} enabled - Enable the dashboard resource map used by the tenant UI. ## @param {Monitoring} monitoring - Monitoring configuration. monitoring: diff --git a/packages/system/foundationdb-rd/cozyrds/foundationdb.yaml b/packages/system/foundationdb-rd/cozyrds/foundationdb.yaml index a1c2e859a..dbf3ad9f4 100644 --- a/packages/system/foundationdb-rd/cozyrds/foundationdb.yaml +++ b/packages/system/foundationdb-rd/cozyrds/foundationdb.yaml @@ -8,7 +8,7 @@ spec: singular: foundationdb plural: foundationdbs openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"cluster":{"description":"Cluster configuration.","type":"object","default":{},"required":["faultDomain","processCounts","redundancyMode","storageEngine","version"],"properties":{"faultDomain":{"description":"Fault domain configuration.","type":"object","default":{},"required":["key","valueFrom"],"properties":{"key":{"description":"Fault domain key.","type":"string","default":"kubernetes.io/hostname"},"valueFrom":{"description":"Fault domain value source.","type":"string","default":"spec.nodeName"}}},"processCounts":{"description":"Process counts for different roles.","type":"object","default":{},"required":["cluster_controller","stateless","storage"],"properties":{"cluster_controller":{"description":"Number of cluster controller processes.","type":"integer","default":1},"stateless":{"description":"Number of stateless processes (-1 for automatic).","type":"integer","default":-1},"storage":{"description":"Number of storage processes (determines cluster size).","type":"integer","default":3}}},"redundancyMode":{"description":"Database redundancy mode (single, double, triple, three_datacenter, three_datacenter_fallback).","type":"string","default":"double"},"storageEngine":{"description":"Storage engine (ssd-2, ssd-redwood-v1, ssd-rocksdb-v1, memory).","type":"string","default":"ssd-2"},"version":{"description":"Version of FoundationDB to use.","type":"string","default":"7.3.63"}}},"storage":{"description":"Storage configuration.","type":"object","default":{},"required":["size","storageClass"],"properties":{"size":{"description":"Size of persistent volumes for each instance.","default":"16Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"Storage class (if not set, uses cluster default).","type":"string","default":"","x-kubernetes-validations":[{"rule":"self == oldSelf","message":"storageClass is immutable"}],"x-cozystack-options":{"source":"storageclass"}}}},"resources":{"description":"Explicit CPU and memory configuration for each FoundationDB instance. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each instance.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each instance.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"c1.small","enum":["t1.nano","t1.micro","t1.small","t1.medium","t1.large","t1.xlarge","t1.2xlarge","t1.4xlarge","c1.nano","c1.micro","c1.small","c1.medium","c1.large","c1.xlarge","c1.2xlarge","c1.4xlarge","s1.nano","s1.micro","s1.small","s1.medium","s1.large","s1.xlarge","s1.2xlarge","s1.4xlarge","u1.nano","u1.micro","u1.small","u1.medium","u1.large","u1.xlarge","u1.2xlarge","u1.4xlarge","m1.nano","m1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m1.2xlarge","m1.4xlarge","nano","micro","small","medium","large","xlarge","2xlarge"]},"backup":{"description":"DEPRECATED Backup configuration (use the Cozystack backups framework: BackupClass + FoundationDB strategy).","type":"object","default":{},"required":["enabled","retentionPolicy","s3"],"properties":{"enabled":{"description":"DEPRECATED Enable in-chart backups (superseded by BackupClass + FoundationDB strategy).","type":"boolean","default":false},"retentionPolicy":{"description":"DEPRECATED Retention policy for backups.","type":"string","default":"7d"},"s3":{"description":"DEPRECATED S3 configuration for backups.","type":"object","default":{},"required":["bucket","credentials","endpoint","region"],"properties":{"bucket":{"description":"DEPRECATED S3 bucket name.","type":"string","default":""},"credentials":{"description":"DEPRECATED S3 credentials.","type":"object","default":{},"required":["accessKeyId","secretAccessKey"],"properties":{"accessKeyId":{"description":"DEPRECATED S3 access key ID.","type":"string","default":""},"secretAccessKey":{"description":"DEPRECATED S3 secret access key.","type":"string","default":""}}},"endpoint":{"description":"DEPRECATED S3 endpoint URL.","type":"string","default":""},"region":{"description":"DEPRECATED S3 region.","type":"string","default":"us-east-1"}}}}},"monitoring":{"description":"Monitoring configuration.","type":"object","default":{},"required":["enabled"],"properties":{"enabled":{"description":"Enable WorkloadMonitor integration.","type":"boolean","default":true}}},"customParameters":{"description":"Custom parameters to pass to FoundationDB.","type":"array","default":[],"items":{"type":"string"}},"imageType":{"description":"Container image deployment type.","type":"string","default":"split","enum":["unified","split"]},"securityContext":{"description":"Security context for containers.","type":"object","default":{},"required":["runAsGroup","runAsUser"],"properties":{"runAsGroup":{"description":"Group ID to run the container.","type":"integer","default":4059},"runAsUser":{"description":"User ID to run the container.","type":"integer","default":4059}}},"automaticReplacements":{"description":"Enable automatic pod replacements.","type":"boolean","default":true}}} + {"title":"Chart Values","type":"object","properties":{"cluster":{"description":"Cluster configuration.","type":"object","default":{},"required":["faultDomain","processCounts","redundancyMode","storageEngine","version"],"properties":{"faultDomain":{"description":"Fault domain configuration.","type":"object","default":{},"required":["key","valueFrom"],"properties":{"key":{"description":"Fault domain key.","type":"string","default":"kubernetes.io/hostname"},"valueFrom":{"description":"Fault domain value source.","type":"string","default":"spec.nodeName"}}},"processCounts":{"description":"Process counts for different roles.","type":"object","default":{},"required":["cluster_controller","stateless","storage"],"properties":{"cluster_controller":{"description":"Number of cluster controller processes.","type":"integer","default":1},"stateless":{"description":"Number of stateless processes (-1 for automatic).","type":"integer","default":-1},"storage":{"description":"Number of storage processes (determines cluster size).","type":"integer","default":3}}},"redundancyMode":{"description":"Database redundancy mode (single, double, triple, three_datacenter, three_datacenter_fallback).","type":"string","default":"double"},"storageEngine":{"description":"Storage engine (ssd-2, ssd-redwood-v1, ssd-rocksdb-v1, memory).","type":"string","default":"ssd-2"},"version":{"description":"Version of FoundationDB to use.","type":"string","default":"7.3.63"}}},"storage":{"description":"Storage configuration.","type":"object","default":{},"required":["size","storageClass"],"properties":{"size":{"description":"Size of persistent volumes for each instance.","default":"16Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"Storage class (if not set, uses cluster default).","type":"string","default":"","x-kubernetes-validations":[{"rule":"self == oldSelf","message":"storageClass is immutable"}],"x-cozystack-options":{"source":"storageclass"}}}},"resources":{"description":"Explicit CPU and memory configuration for each FoundationDB instance. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each instance.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each instance.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"c1.small","enum":["t1.nano","t1.micro","t1.small","t1.medium","t1.large","t1.xlarge","t1.2xlarge","t1.4xlarge","c1.nano","c1.micro","c1.small","c1.medium","c1.large","c1.xlarge","c1.2xlarge","c1.4xlarge","s1.nano","s1.micro","s1.small","s1.medium","s1.large","s1.xlarge","s1.2xlarge","s1.4xlarge","u1.nano","u1.micro","u1.small","u1.medium","u1.large","u1.xlarge","u1.2xlarge","u1.4xlarge","m1.nano","m1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m1.2xlarge","m1.4xlarge","nano","micro","small","medium","large","xlarge","2xlarge"]},"backup":{"description":"DEPRECATED Backup configuration (use the Cozystack backups framework: BackupClass + FoundationDB strategy).","type":"object","default":{},"required":["enabled","retentionPolicy","s3"],"properties":{"enabled":{"description":"DEPRECATED Enable in-chart backups (superseded by BackupClass + FoundationDB strategy).","type":"boolean","default":false},"retentionPolicy":{"description":"DEPRECATED Retention policy for backups.","type":"string","default":"7d"},"s3":{"description":"DEPRECATED S3 configuration for backups.","type":"object","default":{},"required":["bucket","credentials","endpoint","region"],"properties":{"bucket":{"description":"DEPRECATED S3 bucket name.","type":"string","default":""},"credentials":{"description":"DEPRECATED S3 credentials.","type":"object","default":{},"required":["accessKeyId","secretAccessKey"],"properties":{"accessKeyId":{"description":"DEPRECATED S3 access key ID.","type":"string","default":""},"secretAccessKey":{"description":"DEPRECATED S3 secret access key.","type":"string","default":""}}},"endpoint":{"description":"DEPRECATED S3 endpoint URL.","type":"string","default":""},"region":{"description":"DEPRECATED S3 region.","type":"string","default":"us-east-1"}}}}},"monitoring":{"description":"Monitoring configuration.","type":"object","default":{},"required":["enabled"],"properties":{"enabled":{"description":"Enable the dashboard resource map used by the tenant UI.","type":"boolean","default":true}}},"customParameters":{"description":"Custom parameters to pass to FoundationDB.","type":"array","default":[],"items":{"type":"string"}},"imageType":{"description":"Container image deployment type.","type":"string","default":"split","enum":["unified","split"]},"securityContext":{"description":"Security context for containers.","type":"object","default":{},"required":["runAsGroup","runAsUser"],"properties":{"runAsGroup":{"description":"Group ID to run the container.","type":"integer","default":4059},"runAsUser":{"description":"User ID to run the container.","type":"integer","default":4059}}},"automaticReplacements":{"description":"Enable automatic pod replacements.","type":"boolean","default":true}}} release: prefix: foundationdb- labels: