Skip to content

Configuration

The miroir chart installs only the driver; its values are documented value-by-value in the generated chart README (kept in sync with values.yaml by helm-docs; CI fails if it goes stale). The storage configuration (MiroirNode/MiroirNodeGroup custom resources, StorageClasses, and VolumeSnapshotClasses) is plain manifests (Quickstart shows the layouts; kubectl explain miroirnode.spec is the topology reference). This page is the orientation layer: which groups of chart values exist, where their behavior is explained, and every StorageClass parameter.

  • drbd: replication tuning. portBase (Coexistence), onIoError, resync knobs, verify.algorithm / verify.schedule (verification).
  • Root-level behavior knobs (the chart root is the controller): autoTieBreaker (Replication and quorum), autoDiskfulAfter (auto-diskful), autoEvictAfter (resilience), overcommitRatio / freeSpaceRatio, provisionTimeout, storageCapacity, groupSnapshots (Quickstart → Group snapshots).
  • gateway: the per-RWX-volume NFS gateway. enabled (RWX is opt-in, off by default) and the gateway image (ReadWriteMany).
  • monitoring: PodMonitor, PrometheusRule, dashboards (Monitoring).
  • agent / sidecars (and the root's image/resources): workload knobs for images, resources, agent.kubeletDir, agent.loopfileBaseDirs (hostPath mounts for loopfile pools: pod spec the chart cannot derive from your CRs).
  • logging: level and encoder for both components.

StorageClass parameters

A miroir class is a standard StorageClass with provisioner: miroir.home-operations.com and these parameters (all values are strings; quote the numbers and booleans):

Parameter Default Meaning
miroir.home-operations.com/replicas "1" Replica count, 1–3. Above 1 the volume is DRBD-replicated.
miroir.home-operations.com/pool default The named storage pool the class provisions from. Every replica of a volume lands in this pool on its node, so the pool must exist (in the MiroirNode specs) on at least replicas nodes.
miroir.home-operations.com/quorum freeze Replicated only: freeze never diverges but halts writes without a peer majority; last-man-standing keeps the survivor writable at the risk of split-brain. See Replication and quorum.
miroir.home-operations.com/allowRemoteVolumeAccess "true" Replicated only: pods on nodes without a replica consume the volume through an ephemeral diskless DRBD leg at replication-network speed. "false" pins pods to replica nodes for local reads. See Remote consumers.
miroir.home-operations.com/bitmapGranularity absent (DRBD 4096) Replicated only: DRBD bitmap block size in bytes, a power of two 4096–1048576. Coarser cuts bitmap RAM proportionally but resyncs more per dirty bit; worth considering for classes holding large volumes. Fixed when a replica's metadata is created: changing the class affects new volumes only.
csi.storage.k8s.io/fstype ext4 ext4 or xfs.

The standard StorageClass fields behave as usual, with two worth writing explicitly, because the Kubernetes defaults are rarely what you want: volumeBindingMode: WaitForFirstConsumer (delays provisioning until a pod schedules, so placement can prefer that pod's node; the default Immediate provisions on PVC creation, reasonable only for a replicated class consumed remotely) and allowVolumeExpansion: true (the default forbids online expansion). reclaimPolicy, mountOptions, and the storageclass.kubernetes.io/is-default-class annotation work exactly as documented upstream.

VolumeSnapshotClasses need only driver: miroir.home-operations.com and a deletionPolicy (Quickstart has the manifest; the snapshot-controller and its CRDs deploy separately). PVC clones (dataSource: {kind: PersistentVolumeClaim}) need no class of their own; the clone's StorageClass just has to match the source volume's replicas and pool (Quickstart → Clone a PVC). VolumeGroupSnapshotClasses take exactly the same two fields as a VolumeSnapshotClass, but the feature is off by default: it needs groupSnapshots.enabled: true in the chart plus the cluster-side group snapshot CRDs and feature gate; Quickstart → Group snapshots lists all three switches.

ZFS zvol settings

Each ZFS pool can tune properties for newly created zvols:

  • zfs.volBlockSize accepts 4K, 8K, 16K, 32K, 64K, or 128K (canonical spelling, uppercase K). It defaults to 4K. OpenZFS requires volsize alignment, so miroir rounds new volume sizes up to this boundary. Expansion follows the existing zvol's actual block size, including for snapshot restores and PVC clones.
  • zfs.compression defaults to lz4. Set it to inherit to omit a per-zvol property and use the parent dataset policy. It also accepts OpenZFS on, off, lzjb, zle, gzip levels, zstd levels, and zstd-fast levels (lowercase, as zfs(8) spells them).
apiVersion: miroir.home-operations.com/v1alpha1
kind: MiroirNode
metadata:
  name: paris
spec:
  pools:
    - name: default
      zfs:
        dataset: data-pool/miroir
        volBlockSize: 16K
        compression: inherit

These settings apply only when miroir creates a zvol. Reconciliation does not mutate existing volumes, and snapshot restores and PVC clones retain their source volume's properties.

The complete values.yaml

The block below is the chart's real charts/miroir/values.yaml, pulled in at build time (MkDocs snippets), so the documented defaults can never drift from the file Helm actually renders.

# -- Override the chart name used in labels and default object names.
nameOverride: ""
# -- Override the fully qualified name prefix of every rendered object.
fullnameOverride: ""

# Fleet-wide defaults (kopiur layout). imagePullSecrets and commonLabels
# reach every pod/object; the scheduling globals apply to the controller —
# the only freely schedulable workload (the agent DaemonSet must run on
# every schedulable node for the CSI node service).
global:
  # -- Pull secrets added to every pod (controller, agent, uninstall).
  imagePullSecrets: []
  # -- Labels stamped on every rendered object (fleet-wide labelling).
  commonLabels: {}
  # -- Controller scheduling defaults.
  nodeSelector: {}
  tolerations: []
  affinity: {}

# Both processes bind the controller-runtime zap flags.
logging:
  # -- Log level: debug | info | error (or any zapcore level).
  level: info
  # -- Encoder: json (structured, default) or console (human-readable).
  format: json

# =============================================================================
# Controller (root = controller, kopiur layout; components nest below)
# =============================================================================
# -- Controller image (distroless, no storage userland — the controller never
# execs a storage CLI).
image:
  repository: ghcr.io/home-operations/miroir-controller
  # Overrides the image tag; defaults to the chart appVersion so the chart and
  # image versions stay in lock-step (set to e.g. "main" to track the rolling tag).
  tag: ""
  # Pins the image by digest (sha256:…); when set it takes precedence over the tag.
  # The release pipeline fills this with the published image's digest.
  digest: ""
  pullPolicy: IfNotPresent

# -- system-cluster-critical protects the single controller from eviction
# under node pressure — while it is down, no volume can be provisioned,
# expanded, or snapshotted.
priorityClassName: system-cluster-critical
# -- Wait for agents to realise a new volume. Keep sidecars.*.timeout at or
# above this, or the sidecar RPC deadline fires before this one and the
# knob has no effect.
provisionTimeout: 120s
# -- Thin-provisioning overcommit guardrail: CreateVolume is refused when a
# node's provisioned total would exceed capacity × this ratio. 2× is the
# classic CoW headroom; raise it only if you trust your usage to stay
# sparse, lower it toward 1 to provision conservatively.
overcommitRatio: 2
# -- Physical-space guardrail: CreateVolume is refused when the request would
# exceed the pool's *free* bytes × this ratio. overcommitRatio alone bounds
# virtual bytes, so a pool whose thin volumes have actually filled it can
# still admit more; running a pool out of space surfaces as I/O errors under
# live volumes rather than a clean refusal. 20× matches LINSTOR and BlockStor
# and only bites once a pool is ~90% full; lower it toward 1 to keep more
# physical headroom in reserve.
freeSpaceRatio: 20
# -- Add a diskless tie-breaker replica to 2-replica freeze volumes when a
# spare storage node exists, so majority quorum survives a single node
# loss. Also retrofits existing freeze volumes at controller startup.
autoTieBreaker: true
# -- Convert a diskless leg (client or tie-breaker) that has stayed DRBD
# Primary past this duration into a local diskful replica on its node, so a
# settled consumer stops paying network I/O (LINSTOR's auto-diskful; Go
# duration, e.g. "10m"). Conversion needs a MiroirNode for the leg's node
# with fresh pool stats and room for the volume's full size. Empty disables
# it.
# See the root README, "Auto-diskful".
autoDiskfulAfter: ""
# -- Re-place a dead storage node's legs once its heartbeat (MiroirNode
# status, refreshed ~60s) has been stale this long (LINSTOR's auto-evict;
# Go duration, e.g. "60m" — keep it well above any reboot or upgrade
# window). Each affected volume gets one atomic swap: the dead entry out,
# a fresh replica in (full sync follows). The dead node keeps its teardown
# finalizer as the record of its never-cleaned leg: deleting an evicted
# volume still waits for that node, and when the node returns its agent
# tears the leftover leg down through the normal removal flow.
# It never acts when more than one node looks dead, when a survivor still
# sees the node's DRBD links up, when the remaining legs are not clean,
# or when snapshots pin the volume. Needs a spare storage node carrying
# the volume's pool; per-node opt-out via `spec.autoEvict: false` on its MiroirNode.
# Empty disables it (the default: eviction discards the dead node's data).
autoEvictAfter: ""
# Storage-capacity-aware scheduling. When enabled, the external-provisioner
# publishes CSIStorageCapacity objects from the driver's GetCapacity RPC
# (capacity × overcommitRatio − provisioned, per storage node) and the
# kube-scheduler steers a WaitForFirstConsumer pod onto a node whose pool can
# hold the volume — instead of landing there and having CreateVolume refuse it
# and reschedule. CreateVolume's own overcommit guard stays the authority.
# Off by default: it is a behavior change — with storageCapacity on, the
# scheduler treats a (node, class) pair with no published capacity as unfit, so
# a freshly installed cluster waits for agents to publish pool stats (up to
# agent.poolStatsInterval) before the first pod schedules.
storageCapacity:
  enabled: false
# Volume group snapshots: crash-consistent snapshots cut across several
# PVCs at once under one shared write barrier (VolumeGroupSnapshot API).
# Off by default because it needs cluster-side pieces the chart does not
# ship: the groupsnapshot.storage.k8s.io v1 CRDs and a
# snapshot-controller running with --feature-gates=CSIVolumeGroupSnapshot=true
# (the same gate this flag passes to the csi-snapshotter sidecar).
# Only replicated volumes (replicas > 1) can join a group — the DRBD
# write barrier is what makes the cut atomic across volumes.
groupSnapshots:
  enabled: false
# -- Controller replicas. Anything above 1 automatically enables leader
# election: the extras are warm standbys (failover is lease expiry, ~15s,
# instead of a full pod reschedule), the rollout strategy switches to
# RollingUpdate, and a PodDisruptionBudget keeps one replica through
# voluntary disruptions. Pointless on a single-node cluster (the node is
# the failure domain); pair with global.affinity (pod anti-affinity) so
# replicas land on different nodes.
replicaCount: 1
# Leader election turns on by itself when replicaCount > 1 — the
# controller and each CSI sidecar then elect through coordination.k8s.io
# Leases — so this key only customises it.
leaderElection:
  # -- Elect even with a single replica (replicaCount > 1 elects regardless;
  # this can never switch election off above one replica).
  enabled: false
  # -- Lease name; empty derives the release-scoped controller name so two
  # releases in one namespace never share a Lease. Keep it stable across
  # upgrades.
  id: ""
# -- Seconds the controller pod stays bound to an unreachable node before
# eviction. The Kubernetes default (300) leaves a single-replica controller
# unable to provision, expand, or snapshot for five minutes after its node
# dies; 5 reschedules it almost immediately (the controller is stateless).
unreachableNodeTolerationSeconds: 5
# -- Controller resources.
resources:
  requests:
    cpu: 10m
    memory: 32Mi
  limits:
    memory: 128Mi
# -- Extra labels on the controller pod.
podLabels: {}
# -- Extra annotations on the controller pod.
podAnnotations: {}
# -- Extra arguments for the controller container.
extraArgs: []
# -- Extra environment variables for the controller container.
extraEnv: []

# =============================================================================
# CSI sidecars (upstream sig-storage images)
# =============================================================================
sidecars:
  provisioner:
    image: registry.k8s.io/sig-storage/csi-provisioner:v6.3.0
    # LVM/ZFS provisioning on a cold node can exceed the 10s sidecar
    # default; the driver returns DeadlineExceeded and the provisioner
    # retries, but a roomier timeout avoids churn.
    timeout: 120s
    # -- Provisioner sidecar resources.
    resources:
      requests:
        cpu: 10m
        memory: 32Mi
      limits:
        memory: 128Mi
  snapshotter:
    image: registry.k8s.io/sig-storage/csi-snapshotter:v8.6.0
    # CreateSnapshot returns fast (readiness is polled), so the default
    # suffices; raise if snapshot RPCs are slow.
    timeout: 120s
    # -- Snapshotter sidecar resources.
    resources:
      requests:
        cpu: 10m
        memory: 32Mi
      limits:
        memory: 128Mi
  resizer:
    image: registry.k8s.io/sig-storage/csi-resizer:v2.2.1
    # Online grow can block on a rebooting node; keep >= provisionTimeout.
    timeout: 120s
    # -- Resizer sidecar resources.
    resources:
      requests:
        cpu: 10m
        memory: 32Mi
      limits:
        memory: 128Mi

# =============================================================================
# Agent (per-node DaemonSet: storage userland + CSI node service)
# =============================================================================
agent:
  # Agent image (Debian + the lvm/zfs/drbd/mkfs userland the agent execs
  # on each storage node).
  image:
    repository: ghcr.io/home-operations/miroir-agent
    # Overrides the image tag; defaults to the chart appVersion.
    tag: ""
    # Pins the image by digest (sha256:…); takes precedence over the tag.
    # The release pipeline fills this with the published image's digest.
    digest: ""
    pullPolicy: IfNotPresent
  # Per-node backend selection comes from the node's MiroirNode custom
  # resource (see the Storage topology section below).
  #
  # How often each agent republishes its pool capacities to its MiroirNode
  # (read by the controller for capacity-aware placement).
  poolStatsInterval: 60s
  # -- Concurrent volume reconciles per agent. Per-volume work is
  # serialized by controller-runtime regardless; this bounds how many
  # distinct volumes one agent works at once.
  volumeWorkers: 4
  # @schema
  # type: array
  # items:
  #   type: string
  #   pattern: ^/
  # @schema
  # -- Loopfile base directories to hostPath-mount into the agent
  # (identity-mounted: host path == container path). Must list every
  # `loopfile.baseDir` your MiroirNode specs use — the topology lives in
  # CRs the chart cannot read at render time, but the mounts are pod spec.
  # Harmless on nodes without a loopfile pool.
  loopfileBaseDirs: []
  # kubelet plugin-registration sidecar riding the agent DaemonSet.
  registrar:
    image: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.18.0
    # -- Registrar sidecar resources.
    resources:
      requests:
        cpu: 5m
        memory: 16Mi
      limits:
        memory: 64Mi
  # -- Kubelet root on the nodes; CSI sockets and mounts hang off it.
  kubeletDir: /var/lib/kubelet
  resources:
    requests:
      cpu: 10m
      memory: 32Mi
    limits:
      memory: 128Mi
  # -- Extra labels on the agent pods.
  podLabels: {}
  # -- Extra annotations on the agent pods.
  podAnnotations: {}
  # -- Extra arguments for the agent container.
  extraArgs: []
  # -- Extra environment variables for the agent container.
  extraEnv: []

# =============================================================================
# Gateway (per-RWX-volume NFS share manager)
# =============================================================================
# The controller spawns one gateway Deployment per RWX (ReadWriteMany)
# volume: it mounts the volume's device on a replica node and exports it
# over NFSv4 (userspace NFS-Ganesha), which consumers on any node mount.
# The image is the agent userland plus NFS-Ganesha.
gateway:
  # -- Serve ReadWriteMany (and ReadOnlyMany) PVCs via per-volume NFS
  # gateways. Opt-in: gateway pods run privileged in the release namespace,
  # and any user who can create a PVC can cause one to be spawned, so
  # enabling RWX is an explicit operator decision. While disabled the
  # controller rejects RWX at provision time with a clear message, and the
  # gateway ServiceAccount, RBAC, PodMonitor, and export alerts are not
  # installed.
  enabled: false
  image:
    repository: ghcr.io/home-operations/miroir-gateway
    # Overrides the image tag; defaults to the chart appVersion.
    tag: ""
    # Pins the image by digest (sha256:…); takes precedence over the tag.
    # The release pipeline fills this with the published image's digest.
    digest: ""
    pullPolicy: IfNotPresent

# =============================================================================
# Storage configuration (NOT chart values)
# =============================================================================
# This chart installs only the driver. The per-node storage topology
# (MiroirNode/MiroirNodeGroup custom resources), StorageClasses, and
# VolumeSnapshotClasses are plain manifests you apply and version like any
# other Kubernetes object — kubectl rejects unknown fields outright, and
# the CRDs validate the rest. Agents on nodes without a MiroirNode run a
# client-only CSI service and switch to storage mode by themselves when
# their MiroirNode appears.
# See https://miroir.home-operations.com/quickstart/

# =============================================================================
# DRBD replication tuning
# =============================================================================
# DRBD replication tuning applied cluster-wide through the common{} section of
# global_common.conf; every resource inherits it. Leave a value empty to use
# DRBD's built-in default. Tune to your replication network — see the LINBIT
# "Tuning the DRBD Resync Controller" guide.
drbd:
  # @schema
  # type: integer
  # minimum: 1024
  # maximum: 64000
  # @schema
  # -- Lowest TCP port for DRBD replication links, one per replicated volume
  # ascending (7000, 7001, …). The agent runs hostNetwork so these bind on
  # the node's kernel. Ceph mgr dashboard's non-SSL default is also 7000;
  # co-locating with Rook host-network Ceph requires moving one of them
  # (see issue #148). Existing volumes keep their assigned ports.
  portBase: 7000
  # How a diskful replica reacts to a backing-device I/O error. detach
  # (the LINSTOR/DRBD-recommended default) drops the failing leg to
  # Diskless and serves reads/writes via the peer instead of surfacing
  # EIO into the pod. Set to pass_on to propagate errors instead.
  onIoError: detach
  # @schema
  # type: [integer, string]
  # @schema
  # -- disk-timeout in 0.1s units: how long DRBD waits for a backing-device
  # I/O before force-detaching, e.g. 600 (60s). At the DRBD default of 0
  # (infinite) a failing backing disk can wedge a reboot in
  # drbd_md_sync_page_io; but DRBD's manual warns that aborting a request
  # whose completion later arrives can corrupt reused pages or panic the
  # kernel, which is why upstream ships it disabled. Opt in deliberately
  # on hardware known to hang instead of erroring.
  diskTimeout: 0
  # @schema
  # type: [integer, string]
  # @schema
  # -- al-extents, the DRBD activity-log size (number of 4 MiB extents kept
  # "hot"). DRBD's default (1237) forces frequent metadata updates under a
  # scattered random-write workload; raising it (e.g. 6007) cuts that write
  # amplification at the cost of a longer resync of the active region after a
  # crash. Empty leaves DRBD's default. Must be a prime below 65534.
  alExtents: ""
  resync:
    # -- c-plan-ahead in 0.1s units; a value > 0 enables DRBD's variable-rate resync controller.
    planAhead: ""
    # -- c-fill-target, the resync controller's target fill level (e.g. "1M").
    fillTarget: ""
    # -- c-max-rate, the resync bandwidth ceiling used when the link is idle (e.g. "720M").
    maxRate: ""
    # -- c-min-rate, the resync floor guaranteed even under application I/O.
    # Defaulted to 10M: DRBD's kernel default (250 KiB/s) leaves a degraded
    # volume resyncing for days under load; 10 MiB/s heals a 100Gi leg in
    # hours while still yielding most of a 1GbE link to applications. Lower
    # on a slow shared link.
    minRate: 10M
    # -- resync-rate, the fixed rate used only when the controller is off (planAhead empty or 0).
    rate: ""
    # -- rs-discard-granularity cluster-wide fallback: during a full resync,
    # runs of zeroes are sent as discards of this size instead of written
    # out (e.g. "65536"), keeping a re-added thin leg thin. Normally leave
    # empty — the agent probes each lvmthin/zfs backing device and renders
    # an exact per-leg value that overrides this (loopfile is never probed:
    # loop devices mishandle it, so also leave this empty on clusters with
    # loopfile-backed replicated volumes).
    discardGranularity: ""
  net:
    # -- max-buffers, the DRBD receive-buffer count (e.g. "36864"); raises
    # resync throughput on fast links.
    maxBuffers: ""
  verify:
    # -- verify-alg, arming `drbdadm verify <res>` — the only cross-leg
    # integrity check (a zfs scrub only validates one leg against itself).
    # Defaulted to crc32c: drbd.ko depends on libcrc32c so it is present on
    # every node, and it costs nothing until a verify runs. Empty disables
    # verification, including the schedule below.
    algorithm: crc32c
    # -- Cron spec (5-field, agent-local/UTC time) for a scheduled online
    # verify of every replicated volume. The agent initiates it once per
    # volume from the coordinator (first diskful replica), serialized per
    # node, skipping volumes that are resyncing or already verifying.
    # Findings land in the volume's status (`lastVerifyOutOfSyncBytes`), the
    # `miroir_volume_verify_*` metrics, and a `VerifyOutOfSync` event. Empty
    # = no scheduled verify (run it by hand). Requires `algorithm` set.
    schedule: ""
    # -- Pause scheduled verify without dropping the schedule above.
    suspend: false
  # Free-form escape hatch for DRBD options the chart has no knob for:
  # verbatim option lines (semicolons included) appended inside the matching
  # section of common{} in global_common.conf, inherited by every resource.
  # Only validated when an agent next runs drbdadm adjust, and a bad line
  # breaks every resource on the node — test on a throwaway cluster first.
  extraConfig:
    # -- Extra lines for the handlers {} section (e.g. fence handlers).
    handlers: ""
    # -- Extra lines for the startup {} section.
    startup: ""
    # -- Extra lines for the options {} section (resource options).
    options: ""
    # -- Extra lines for the disk {} section
    # (e.g. "read-balancing least-pending;").
    disk: ""
    # -- Extra lines for the net {} section (e.g. "csums-alg crc32c;").
    net: ""

# =============================================================================
# Monitoring
# =============================================================================
# Requires the Prometheus Operator CRDs (deployed separately).
monitoring:
  podMonitor:
    # -- Create a Prometheus Operator PodMonitor (requires its CRDs) scraping
    # the controller and every agent pod on their metrics ports. The
    # per-volume miroir_volume_* gauges are exported by the agents.
    enabled: false
    # -- Scrape interval.
    interval: 30s
    # -- Scrape timeout.
    scrapeTimeout: 10s
    # -- Metrics path.
    path: /metrics
    # -- PodMonitor labels.
    labels: {}
    # -- PodMonitor annotations.
    annotations: {}
    # -- Prometheus metric relabelings.
    metricRelabelings: []
    # -- Extra Prometheus relabelings (applied before scraping); a node
    # label from the pod's node name is always added.
    relabelings: []
    # -- Pod target labels to copy from pods.
    podTargetLabels: []

  prometheusRule:
    # -- Create a PrometheusRule with alerting rules (requires the Prometheus Operator CRDs).
    enabled: false
    # -- PrometheusRule annotations.
    annotations: {}
    # -- PrometheusRule labels.
    labels: {}
    # -- Extra labels added to every alert rule.
    additionalRuleLabels: {}
    # -- Extra annotations added to every alert rule.
    additionalRuleAnnotations: {}
    # -- Per-alert overrides keyed by alert name. Per entry: `disabled: true`
    # drops the rule, `for` replaces the rule's wait period, and `labels`
    # merge over the rule's own (set `severity` here to reclassify one
    # alert). Example:
    #   overrides:
    #     MiroirVolumeOutOfSync: { disabled: true }
    #     MiroirVolumeDisconnected:
    #       for: 30m
    #       labels: { severity: info }
    overrides: {}
    # -- Days since the last completed scheduled verify before
    # MiroirVolumeVerifyStale fires. Size it to just over the schedule
    # period (a weekly `drbd.verify.schedule` → 8). The rule is only
    # rendered when `drbd.verify.schedule` is set.
    verifyStaleDays: 8

  dashboards:
    # -- Render the Grafana dashboard ConfigMap (for grafana-operator or the kube-prometheus-stack sidecar).
    enabled: false
    # -- Namespace for the dashboard objects; defaults to the release namespace.
    namespace: ""
    # -- Annotations added to the dashboard ConfigMap.
    annotations: {}
    # -- Labels added to the dashboard ConfigMap.
    labels: {}
    grafanaOperator:
      # -- Render a GrafanaDashboard CR (grafana-operator) instead of a sidecar ConfigMap.
      enabled: false
      # -- If true allows for a Grafana in any namespace to access this GrafanaDashboard.
      allowCrossNamespaceImport: true
      # -- Folder to create the dashboard in.
      folder: ""
      # -- Resync period for the Grafana operator to check for updates to the dashboard.
      resyncPeriod: "10m"
      # -- Selected labels for Grafana instance.
      matchLabels: {}

# =============================================================================
# Uninstall hook
# =============================================================================
# `helm uninstall` data handling. By default the release is removed but every
# MiroirVolume/MiroirSnapshot — and the data on the nodes — is left in place
# (the CRDs, installed from crds/, survive uninstall too, so a reinstall
# re-adopts everything). Destroying the data is opt-in via `confirmation`.
uninstall:
  # -- Consent to destroy all volume data on `helm uninstall`: set to the
  # literal "yes-really-destroy-data" to render the pre-delete hook Job that
  # deletes every MiroirSnapshot and MiroirVolume — the agents then tear down
  # each DRBD resource and backing device, including volumes whose PV
  # reclaimPolicy is Retain. Hooks are baked into the release at
  # install/upgrade time, so set this with a `helm upgrade` *before* running
  # `helm uninstall`. Any other non-empty value fails the render.
  confirmation: ""
  # -- Image for the uninstall hook Job (needs only `kubectl`).
  image: registry.k8s.io/kubectl:v1.37.0