{ "title": "Chart Values", "type": "object", "properties": { "host": { "description": "The hostname used to access Grafana externally (defaults to 'grafana' subdomain for the tenant host).", "type": "string", "default": "" }, "metricsStorages": { "description": "Configuration of metrics storage instances.", "type": "array", "default": [ { "deduplicationInterval": "15s", "name": "shortterm", "retentionPeriod": "3d", "storage": "10Gi", "storageClassName": "" }, { "deduplicationInterval": "5m", "name": "longterm", "retentionPeriod": "14d", "storage": "10Gi", "storageClassName": "" } ], "items": { "type": "object", "required": [ "deduplicationInterval", "name", "retentionPeriod", "storage" ], "properties": { "deduplicationInterval": { "description": "Deduplication interval for metrics.", "type": "string" }, "name": { "description": "Name of the storage instance.", "type": "string" }, "retentionPeriod": { "description": "Retention period for metrics.", "type": "string" }, "storage": { "description": "Persistent volume size.", "type": "string", "default": "10Gi" }, "storageClassName": { "description": "StorageClass used for the data.", "type": "string" }, "vminsert": { "description": "Configuration for vminsert.", "type": "object", "properties": { "maxAllowed": { "description": "Maximum allowed resources.", "type": "object", "properties": { "cpu": { "description": "CPU limit.", "default": 1, "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 limit.", "default": "1Gi", "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 } } }, "minAllowed": { "description": "Minimum guaranteed resources.", "type": "object", "properties": { "cpu": { "description": "CPU request.", "default": "100m", "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 request.", "default": "256Mi", "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 } } } } }, "vmselect": { "description": "Configuration for vmselect.", "type": "object", "properties": { "maxAllowed": { "description": "Maximum allowed resources.", "type": "object", "properties": { "cpu": { "description": "CPU limit.", "default": 1, "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 limit.", "default": "1Gi", "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 } } }, "minAllowed": { "description": "Minimum guaranteed resources.", "type": "object", "properties": { "cpu": { "description": "CPU request.", "default": "100m", "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 request.", "default": "256Mi", "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 } } } } }, "vmstorage": { "description": "Configuration for vmstorage.", "type": "object", "properties": { "maxAllowed": { "description": "Maximum allowed resources.", "type": "object", "properties": { "cpu": { "description": "CPU limit.", "default": 1, "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 limit.", "default": "1Gi", "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 } } }, "minAllowed": { "description": "Minimum guaranteed resources.", "type": "object", "properties": { "cpu": { "description": "CPU request.", "default": "100m", "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 request.", "default": "256Mi", "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 } } } } } } } }, "logsStorages": { "description": "Configuration of logs storage instances.", "type": "array", "default": [ { "name": "generic", "retentionPeriod": "1", "storage": "10Gi", "storageClassName": "replicated" } ], "items": { "type": "object", "required": [ "name", "retentionPeriod", "storage", "storageClassName" ], "properties": { "name": { "description": "Name of the storage instance.", "type": "string" }, "retentionPeriod": { "description": "Retention period for logs.", "type": "string", "default": "1" }, "storage": { "description": "Persistent volume size.", "type": "string", "default": "10Gi" }, "storageClassName": { "description": "StorageClass used to store the data.", "type": "string", "default": "replicated" } } } }, "alerta": { "description": "Configuration for the Alerta service.", "type": "object", "default": {}, "properties": { "alerts": { "description": "Alert routing configuration.", "type": "object", "default": {}, "properties": { "slack": { "description": "Configuration for Slack alerts.", "type": "object", "default": {}, "required": [ "url" ], "properties": { "disabledSeverity": { "description": "List of severities without alerts (e.g. [\"informational\",\"warning\"]).", "type": "array", "default": [], "items": { "type": "string" } }, "url": { "description": "Configuration uri for Slack alerts.", "type": "string", "default": "" } } }, "telegram": { "description": "Configuration for Telegram alerts.", "type": "object", "default": {}, "required": [ "chatID", "token" ], "properties": { "chatID": { "description": "Telegram chat ID(s), separated by commas.", "type": "string", "default": "" }, "disabledSeverity": { "description": "List of severities without alerts (e.g. [\"informational\",\"warning\"]).", "type": "array", "default": [], "items": { "type": "string" } }, "token": { "description": "Telegram bot token.", "type": "string", "default": "" } } } } }, "resources": { "description": "Resource configuration.", "type": "object", "default": {}, "properties": { "limits": { "description": "Resource limits.", "type": "object", "default": {}, "properties": { "cpu": { "description": "CPU limit.", "default": 1, "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 limit.", "default": "1Gi", "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 } } }, "requests": { "description": "Resource requests.", "type": "object", "default": {}, "properties": { "cpu": { "description": "CPU request.", "default": "100m", "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 request.", "default": "256Mi", "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 } } } } }, "storage": { "description": "Persistent volume size for the database.", "type": "string", "default": "10Gi" }, "storageClassName": { "description": "StorageClass used for the database.", "type": "string", "default": "" } } }, "grafana": { "description": "Configuration for Grafana.", "type": "object", "default": {}, "properties": { "db": { "description": "Database configuration.", "type": "object", "default": {}, "properties": { "size": { "description": "Persistent volume size for the database.", "type": "string", "default": "10Gi" } } }, "resources": { "description": "Resource configuration.", "type": "object", "default": {}, "properties": { "limits": { "description": "Resource limits.", "type": "object", "default": {}, "properties": { "cpu": { "description": "CPU limit.", "default": 1, "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 limit.", "default": "1Gi", "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 } } }, "requests": { "description": "Resource requests.", "type": "object", "default": {}, "properties": { "cpu": { "description": "CPU request.", "default": "100m", "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 request.", "default": "256Mi", "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 } } } } } } }, "vmagent": { "description": "Configuration for VictoriaMetrics Agent.", "type": "object", "default": {}, "properties": { "externalLabels": { "description": "External labels applied to all metrics.", "type": "object", "default": { "cluster": "cozystack" } }, "remoteWrite": { "description": "Remote write configuration.", "type": "object", "default": { "urls": [ "http://vminsert-shortterm:8480/insert/0/prometheus", "http://vminsert-longterm:8480/insert/0/prometheus" ] } } } }, "oidc": { "description": "OIDC authentication for the Grafana instance. See docs/oidc-grafana.md for the operator guide.", "type": "object", "default": {}, "required": [ "mode" ], "properties": { "customConfig": { "description": "Tenant-supplied `[auth.generic_oauth]` payload; consumed only when `mode: CustomConfig`.", "type": "object", "default": {}, "properties": { "config": { "description": "Inline map of `[auth.generic_oauth]` keys. Written verbatim into the Grafana CR `spec.config`. Mutually exclusive with `secretRef.name`.", "type": "object", "default": {} }, "secretRef": { "description": "Reference to a Secret holding an `auth.ini` fragment; mounted under `/etc/grafana/oidc` and loaded via `GF_PATHS_CUSTOM_INI`.", "type": "object", "default": {}, "properties": { "name": { "description": "Name of an existing Secret in the release namespace whose `auth.ini` key holds a ready-made `[auth.generic_oauth]` block. Mutually exclusive with `customConfig.config`.", "type": "string", "default": "" } } } } }, "mode": { "description": "Identity mode. `None`: no OIDC, only the `grafana-admin-password` Secret works. `System`: trust the platform `cozy` realm via a per-instance confidential client and audience binding; zero-config default. `CustomConfig`: trust a tenant-supplied issuer directly (BYO); `cozy` is not in the path.", "type": "string", "default": "None", "enum": [ "None", "System", "CustomConfig" ] }, "users": { "description": "Users granted access to this Grafana instance's org. Each entry is reconciled into Grafana org membership + role by a chart-owned post-install/post-upgrade Job. Works for both `System` and `CustomConfig` modes; ignored when `mode: None`. Users not listed here get nothing (no default org role from group mapping).", "type": "array", "default": [], "items": { "type": "object", "required": [ "email", "role" ], "properties": { "email": { "description": "Email address matched against the `email` claim from the issuer. The chart pre-provisions a Grafana account with this email so the users-Job can set the org role before the operator's first login (`oauth_allow_insecure_email_lookup = true` glues the two together). Must match a conservative pattern: local part is `[A-Za-z0-9._%+-]+`, domain is `[A-Za-z0-9.-]+\\.[A-Za-z]{2,}`. Whitespace, quoted literals, and unusual URL-reserved characters are rejected on schema level so the reconcile-Job's shell handling never has to defend against malformed input.", "type": "string" }, "role": { "description": "Grafana org role to bind: `Admin`, `Editor`, or `Viewer`. Applied to the release's Grafana org (`Main Org.`); server-level `GrafanaAdmin` promotion is out of scope for Phase 1. Required — the users-Job POSTs `{loginOrEmail, role}` to `/api/orgs/1/users` and PATCHes `{role}` to converge across re-runs; omitting the field would render `role: \"null\"` into the body and fail with HTTP 400.", "type": "string", "enum": [ "Admin", "Editor", "Viewer" ] } } } } } } } }