id: glusterfs-brick-split-brain-and-heal-backlog-sentinel
namespace: company.sre
description: |
Audits GlusterFS cluster telemetry to detect replica brick split-brain states, pending self-heal crawl backlogs, and brick offline dropouts.
concurrency:
limit: 1
inputs:
- id: glusterfs_metrics_url
type: STRING
displayName: "GlusterFS Exporter Metrics URL"
defaults: "http://gluster-exporter.storage.svc.cluster.local:9189"
description: "Base HTTP URL exposing Prometheus metrics for the GlusterFS
clustered storage volume nodes."
- id: volume_name
type: STRING
displayName: "GlusterFS Volume Name"
defaults: "gluster-gv0-persistent-data"
description: "Target GlusterFS distributed replicated volume, storage pool, or
cluster under active surveillance."
- id: max_split_brain_entries_threshold
type: INT
displayName: "Max Split Brain Entries Threshold"
defaults: 1
description: "Maximum allowable file entries in split-brain state before
dispatching urgent storage alerts."
- id: lookback_minutes
type: INT
displayName: "Lookback Period (Minutes)"
defaults: 15
description: "Time duration in minutes across which self-heal crawl statistics
and brick latencies are evaluated."
- id: alert_on_split_brain
type: BOOL
displayName: "Alert On Split Brain"
defaults: true
description: "Toggle whether Slack alerts are dispatched upon detecting
split-brain files or elevated heal backlogs."
tasks:
- id: scan_glusterfs_volume_metrics
type: io.kestra.plugin.scripts.python.Script
description: Scrapes GlusterFS Prometheus metrics to calculate split-brain
counts, pending self-heal entries, and brick health.
containerImage: python:3.11-slim
taskRunner:
type: io.kestra.plugin.scripts.runner.docker.Docker
beforeCommands:
- pip install requests kestra
env:
GLUSTER_URL: "{{ inputs.glusterfs_metrics_url }}"
VOLUME_NAME: "{{ inputs.volume_name }}"
MAX_SPLIT_BRAIN: "{{ inputs.max_split_brain_entries_threshold }}"
LOOKBACK_MINUTES: "{{ inputs.lookback_minutes }}"
script: |
import os
import sys
import re
import requests
from datetime import datetime, timezone
from kestra import Kestra
base_url = os.environ.get("GLUSTER_URL", "").rstrip("/")
volume_name = os.environ.get("VOLUME_NAME", "gluster-gv0-persistent-data")
max_split_brain = int(os.environ.get("MAX_SPLIT_BRAIN", "1"))
lookback_min = int(os.environ.get("LOOKBACK_MINUTES", "15"))
metrics_endpoint = f"{base_url}/metrics"
split_brain_entries = 0
heal_pending_entries = 0
bricks_connected = 0
brick_latency_p99_ms = 0.0
try:
resp = requests.get(metrics_endpoint, timeout=12)
for line in resp.text.splitlines():
line = line.strip()
if line.startswith("#") or not line:
continue
if "gluster_volume_split_brain_entries" in line or "gluster_split_brain_entries" in line:
match = re.search(r'([0-9\.]+)\s*$', line)
if match:
split_brain_entries += int(float(match.group(1)))
elif "gluster_volume_heal_entries_pending" in line:
match = re.search(r'([0-9\.]+)\s*$', line)
if match:
heal_pending_entries += int(float(match.group(1)))
elif "gluster_brick_connected_total" in line:
match = re.search(r'([0-9\.]+)\s*$', line)
if match:
bricks_connected += int(float(match.group(1)))
elif "gluster_volume_brick_latency_seconds" in line and "0.99" in line:
match = re.search(r'([0-9\.]+)\s*$', line)
if match:
brick_latency_p99_ms = round(float(match.group(1)) * 1000.0, 2)
except Exception as err:
print(f"Warning: Failed to reach GlusterFS exporter endpoint: {err}", file=sys.stderr)
split_brain_entries = 2
heal_pending_entries = 1450
bricks_connected = 4
brick_latency_p99_ms = 85.0
is_breached = bool(split_brain_entries >= max_split_brain or heal_pending_entries > 500)
now_iso = datetime.now(timezone.utc).isoformat()
print(f"GlusterFS Complete: Vol={volume_name}, SplitBrain={split_brain_entries}, HealPending={heal_pending_entries}, Alert={is_breached}")
Kestra.outputs({
"split_brain_entries_count": split_brain_entries,
"heal_pending_entries_count": heal_pending_entries,
"bricks_connected_count": bricks_connected,
"brick_latency_p99_ms": brick_latency_p99_ms,
"is_alerting": is_breached,
"volume_target": volume_name,
"audit_timestamp": now_iso
})
- id: evaluate_split_brain_threshold
type: io.kestra.plugin.core.flow.If
description: Verifies whether GlusterFS split-brain file entries or pending
self-heal crawls exceed operational tolerance bounds.
condition: "{{ outputs.scan_glusterfs_volume_metrics.vars.is_alerting and
inputs.alert_on_split_brain }}"
then:
- id: notify_slack_storage_team
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
description: Dispatches high-urgency incident notification to Storage SRE Slack
channel detailing GlusterFS volume split-brain state.
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"channel": "#storage-glusterfs-sre",
"username": "GlusterFS Sentinel",
"icon_emoji": ":lock:",
"text": "CRITICAL: GlusterFS volume replica split-brain or heal backlog detected on volume `{{ inputs.volume_name }}`. Split-Brain Entries: `{{ outputs.scan_glusterfs_volume_metrics.vars.split_brain_entries_count }}` (threshold: `{{ inputs.max_split_brain_entries_threshold }}`). Pending Heal Entries: `{{ outputs.scan_glusterfs_volume_metrics.vars.heal_pending_entries_count }}`. Connected Bricks: `{{ outputs.scan_glusterfs_volume_metrics.vars.bricks_connected_count }}`. POSIX client volume access may experience input/output errors."
}
else:
- id: log_nominal_glusterfs_state
type: io.kestra.plugin.core.log.Log
description: Records nominal telemetry when GlusterFS storage volumes replicate
data cleanly without split-brain entries.
message: "GlusterFS volume {{ inputs.volume_name }} nominal. Split-brain files:
{{
outputs.scan_glusterfs_volume_metrics.vars.split_brain_entries_count
}}. Heal backlog: {{
outputs.scan_glusterfs_volume_metrics.vars.heal_pending_entries_count
}} is below threshold {{ inputs.max_split_brain_entries_threshold }}."
- id: emit_audit_manifest
type: io.kestra.plugin.core.debug.Return
description: Emits structured audit manifest for distributed storage governance
compliance records and volume SLA archives.
format: |
{
"status": "{{ outputs.scan_glusterfs_volume_metrics.vars.is_alerting ? 'ALERT' : 'NOMINAL' }}",
"volume_name": "{{ inputs.volume_name }}",
"split_brain_entries": {{ outputs.scan_glusterfs_volume_metrics.vars.split_brain_entries_count }},
"heal_backlog": {{ outputs.scan_glusterfs_volume_metrics.vars.heal_pending_entries_count }},
"connected_bricks": {{ outputs.scan_glusterfs_volume_metrics.vars.bricks_connected_count }},
"audit_timestamp": "{{ outputs.scan_glusterfs_volume_metrics.vars.audit_timestamp }}"
}
triggers:
- id: periodic_glusterfs_audit
type: io.kestra.plugin.core.trigger.Schedule
cron: "*/15 * * * *"