Fix deploy-observability and manage-dashboards issues found during live deployment

deploy-observability:
- Discover DNS from UPLINK config instead of hardcoding 8.8.8.8
- Set ipv4.address on OVN NICs (port security drops unknown IPs)
- Install ca-certificates/curl/gnupg before adding Grafana apt repo
- Fix ACL create syntax (--description flag, not key=value)
- Add NIC recovery after ACL changes (NICs go DOWN)

manage-dashboards:
- Rewrite read_manifest() without PyYAML dependency
- Fix ensure_folder() mixing debug output with return value
- Rewrite install payload generation with heredoc + file I/O
- Separate incus file push from Grafana API call
- Fix while-read loops consuming stdin from incus exec (fd3)

Dashboard JSON:
- Add allValue:".*" to all template variables with includeAll

Screenshots:
- Add Playwright screenshots of all 9 Grafana dashboards

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Maarten 2026-02-25 08:54:58 +01:00
parent 6c7714459b
commit f1f85d21ea
17 changed files with 3837 additions and 862 deletions

View File

@ -233,21 +233,41 @@ phase_deploy_monitoring() {
-c limits.memory=2GiB \ -c limits.memory=2GiB \
-d root,size=20GiB -d root,size=20GiB
# Tell OVN the static IP we want — port security drops traffic from
# IPs that OVN didn't assign, so this must be set at the device level.
incus config device set "$(container_ref monitoring)" eth0 \
ipv4.address="${MONITORING_IP}"
info "Waiting for container agent..." info "Waiting for container agent..."
wait_for_container_agent monitoring 60 wait_for_container_agent monitoring 60
# Configure static IP # Discover upstream DNS from the UPLINK network config.
# OVN DHCP advertises this automatically, but we need it for the static
# networkd config (which bypasses DHCP).
local upstream_dns
upstream_dns=$(incus network get "${CLUSTER_REMOTE}:UPLINK" dns.nameservers 2>/dev/null) || true
upstream_dns="${upstream_dns:-192.168.100.1}"
detail "Using upstream DNS: ${upstream_dns}"
# Build DNS lines (handles comma-separated list from UPLINK config)
local dns_lines=""
IFS=',' read -ra dns_addrs <<< "$upstream_dns"
for addr in "${dns_addrs[@]}"; do
dns_lines="${dns_lines}DNS=${addr}"$'\n'
done
# Configure matching static IP inside the container (systemd-networkd
# bypasses DHCP, so we must specify DNS explicitly).
container_exec monitoring bash -c " container_exec monitoring bash -c "
cat > /etc/systemd/network/10-static.network << 'NETCFG' cat > /etc/systemd/network/10-static.network << NETCFG
[Match] [Match]
Name=eth0 Name=eth0
[Network] [Network]
Address=${MONITORING_IP}/24 Address=${MONITORING_IP}/24
Gateway=10.10.10.1 Gateway=10.10.10.1
DNS=10.10.10.1 ${dns_lines}NETCFG
NETCFG systemctl restart systemd-networkd systemd-resolved
systemctl restart systemd-networkd
" "
sleep 3 sleep 3
@ -281,7 +301,15 @@ phase_install_prometheus() {
container_exec monitoring bash -c " container_exec monitoring bash -c "
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
# Add Grafana apt repository (provides grafana, loki, promtail)
apt-get update -qq apt-get update -qq
apt-get install -y -qq ca-certificates curl gnupg apt-transport-https 2>&1 | tail -1
curl -fsSL https://apt.grafana.com/gpg.key | gpg --dearmor -o /usr/share/keyrings/grafana-archive-keyring.gpg
echo 'deb [signed-by=/usr/share/keyrings/grafana-archive-keyring.gpg] https://apt.grafana.com stable main' \
> /etc/apt/sources.list.d/grafana.list
apt-get update -qq
apt-get install -y -qq prometheus 2>&1 | tail -1 apt-get install -y -qq prometheus 2>&1 | tail -1
# Place Incus client certs where Prometheus can read them # Place Incus client certs where Prometheus can read them
@ -524,6 +552,10 @@ phase_deploy_node_exporters() {
-c limits.memory=128MiB \ -c limits.memory=128MiB \
-c security.privileged=true -c security.privileged=true
# Reserve this IP in OVN before switching to static inside the container
incus config device set "$(container_ref "$name")" eth0 \
ipv4.address="${ip}"
wait_for_container_agent "$name" 30 wait_for_container_agent "$name" 30
# Mount host filesystems for full node metrics # Mount host filesystems for full node metrics
@ -582,14 +614,13 @@ phase_create_acl() {
# Create the ACL if it does not exist # Create the ACL if it does not exist
if ! incus network acl show "$(container_ref monitoring-allow)" &>/dev/null 2>&1; then if ! incus network acl show "$(container_ref monitoring-allow)" &>/dev/null 2>&1; then
incus network acl create "$(container_ref monitoring-allow)" \ incus network acl create "$(container_ref monitoring-allow)"
description="Allow all traffic for observability stack"
# Add allow-all egress and ingress rules # Add allow-all egress and ingress rules
incus network acl rule add "$(container_ref monitoring-allow)" egress \ incus network acl rule add "$(container_ref monitoring-allow)" egress \
action=allow description="Allow all egress" action=allow
incus network acl rule add "$(container_ref monitoring-allow)" ingress \ incus network acl rule add "$(container_ref monitoring-allow)" ingress \
action=allow description="Allow all ingress" action=allow
success "ACL 'monitoring-allow' created with allow-all rules" success "ACL 'monitoring-allow' created with allow-all rules"
else else
success "ACL 'monitoring-allow' already exists" success "ACL 'monitoring-allow' already exists"
@ -615,6 +646,19 @@ phase_create_acl() {
idx=$((idx + 1)) idx=$((idx + 1))
done done
# Changing security.acls can bring the NIC down. Bring all NICs back up.
sleep 2
container_exec monitoring bash -c "ip link set eth0 up; systemctl restart systemd-networkd" 2>/dev/null || true
local nic_idx=1
for ip in "${NODE_EXP_IPS[@]}"; do
local nname
nname=$(node_exp_name "$nic_idx")
if container_exists "$nname"; then
container_exec "$nname" sh -c "ip link set eth0 up; rc-service networking restart" 2>/dev/null || true
fi
nic_idx=$((nic_idx + 1))
done
success "ACL attached to all observability containers" success "ACL attached to all observability containers"
} }
@ -815,6 +859,9 @@ phase_deploy_workload_web() {
--target "oc-node-01" \ --target "oc-node-01" \
-c limits.memory=128MiB -c limits.memory=128MiB
incus config device set "$(container_ref workload-web)" eth0 \
ipv4.address="${WORKLOAD_WEB_IP}"
wait_for_container_agent workload-web 30 wait_for_container_agent workload-web 30
container_exec workload-web sh -c " container_exec workload-web sh -c "
@ -889,6 +936,9 @@ phase_deploy_workload_api() {
--target "oc-node-03" \ --target "oc-node-03" \
-c limits.memory=128MiB -c limits.memory=128MiB
incus config device set "$(container_ref workload-api)" eth0 \
ipv4.address="${WORKLOAD_API_IP}"
wait_for_container_agent workload-api 30 wait_for_container_agent workload-api 30
container_exec workload-api sh -c " container_exec workload-api sh -c "

View File

@ -190,7 +190,7 @@ for f in folders:
" 2>/dev/null || echo "") " 2>/dev/null || echo "")
if [[ -n "$folder_id" ]]; then if [[ -n "$folder_id" ]]; then
detail "Folder '${folder_title}' exists (ID: ${folder_id})" detail "Folder '${folder_title}' exists (ID: ${folder_id})" >&2
echo "$folder_id" echo "$folder_id"
return 0 return 0
fi fi
@ -209,7 +209,7 @@ print(json.load(sys.stdin).get('id', ''))
" 2>/dev/null || echo "") " 2>/dev/null || echo "")
if [[ -n "$folder_id" ]]; then if [[ -n "$folder_id" ]]; then
detail "Created folder '${folder_title}' (ID: ${folder_id})" detail "Created folder '${folder_title}' (ID: ${folder_id})" >&2
echo "$folder_id" echo "$folder_id"
else else
error "Failed to create folder '${folder_title}': ${result}" error "Failed to create folder '${folder_title}': ${result}"
@ -226,21 +226,54 @@ read_manifest() {
fi fi
python3 -c " python3 -c "
import yaml, sys import sys, re
entries = []
current = {}
with open('${MANIFEST_FILE}') as f: with open('${MANIFEST_FILE}') as f:
data = yaml.safe_load(f) for line in f:
stripped = line.rstrip()
# New entry starts with ' - file:'
m = re.match(r'^ - file:\s*(.*)', stripped)
if m:
if current:
entries.append(current)
current = {'file': m.group(1).strip()}
continue
# Key-value within an entry
m = re.match(r'^ (\w+):\s*(.*)', stripped)
if m and current:
key, val = m.group(1), m.group(2).strip()
# Strip YAML >- multiline indicators and quotes
if val in ('>-', '>', '|'):
val = ''
val = val.strip('\"').strip(\"'\")
if key in current and not val:
continue
current[key] = val
continue
# Continuation line (multiline description)
if current and stripped.startswith(' ') and stripped.strip():
if 'description' in current:
sep = ' ' if current['description'] else ''
current['description'] = current['description'] + sep + stripped.strip()
for d in data.get('dashboards', []): if current:
file_path = d.get('file', '') entries.append(current)
uid = d.get('uid', '')
title = d.get('title', '') for d in entries:
folder = d.get('folder', 'General') parts = [
category = d.get('category', '') d.get('file', ''),
version = d.get('version', '1') d.get('uid', ''),
description = d.get('description', '') d.get('title', ''),
print(f'{file_path}\t{uid}\t{title}\t{folder}\t{category}\t{version}\t{description}') d.get('folder', 'General'),
" 2>/dev/null d.get('category', ''),
d.get('version', '1'),
d.get('description', ''),
]
print('\t'.join(parts))
"
} }
# Substitute datasource variables in JSON content # Substitute datasource variables in JSON content
@ -279,7 +312,7 @@ action_install() {
info "(dry-run) Would install dashboards from ${DASHBOARDS_DIR}" info "(dry-run) Would install dashboards from ${DASHBOARDS_DIR}"
local count=0 local count=0
while IFS=$'\t' read -r file uid title folder category version description; do while IFS=$'\t' read -r file uid title folder category version description <&3; do
if [[ -n "$FILTER_CATEGORY" && "$category" != "$FILTER_CATEGORY" ]]; then if [[ -n "$FILTER_CATEGORY" && "$category" != "$FILTER_CATEGORY" ]]; then
continue continue
fi fi
@ -288,7 +321,7 @@ action_install() {
fi fi
info "(dry-run) Would install: ${title} -> folder '${folder}'" info "(dry-run) Would install: ${title} -> folder '${folder}'"
count=$((count + 1)) count=$((count + 1))
done < <(read_manifest) done 3< <(read_manifest)
info "(dry-run) ${count} dashboard(s) would be installed" info "(dry-run) ${count} dashboard(s) would be installed"
return 0 return 0
@ -299,7 +332,7 @@ action_install() {
local installed=0 local installed=0
local failed=0 local failed=0
while IFS=$'\t' read -r file uid title folder category version description; do while IFS=$'\t' read -r file uid title folder category version description <&3; do
if [[ -n "$FILTER_CATEGORY" && "$category" != "$FILTER_CATEGORY" ]]; then if [[ -n "$FILTER_CATEGORY" && "$category" != "$FILTER_CATEGORY" ]]; then
continue continue
fi fi
@ -318,53 +351,24 @@ action_install() {
local folder_id local folder_id
folder_id=$(ensure_folder "$folder") || { failed=$((failed + 1)); continue; } folder_id=$(ensure_folder "$folder") || { failed=$((failed + 1)); continue; }
# Read and process the dashboard JSON # Build Grafana API payload: inject datasource UIDs and wrap in envelope
local raw_json
raw_json=$(cat "$full_path")
# Inject actual datasource UIDs
local processed_json
processed_json=$(inject_datasource_uids "$raw_json")
# Wrap in Grafana API envelope
local api_payload local api_payload
api_payload=$(python3 -c " api_payload=$(python3 - "$full_path" "$PROMETHEUS_UID" "${LOKI_UID:-}" "$folder_id" << 'PYEOF'
import json, sys
dashboard = json.loads('''${processed_json//\'/\\\'}''')
# Remove Grafana-internal fields that shouldn't be in the import
dashboard.pop('id', None)
dashboard.pop('version', None)
dashboard.pop('iteration', None)
payload = {
'dashboard': dashboard,
'folderId': ${folder_id},
'overwrite': True,
'message': 'Installed by manage-dashboards v${VERSION}'
}
print(json.dumps(payload))
" 2>/dev/null)
if [[ -z "$api_payload" ]]; then
# Fallback: use a simpler approach for large/complex JSON
api_payload=$(python3 << 'PYEOF'
import json, sys import json, sys
with open(sys.argv[1]) as f: with open(sys.argv[1]) as f:
dashboard = json.load(f) dashboard = json.load(f)
# Inject datasource UIDs # Inject actual datasource UIDs
json_str = json.dumps(dashboard) json_str = json.dumps(dashboard)
json_str = json_str.replace('${DS_PROMETHEUS}', sys.argv[2]) json_str = json_str.replace('${DS_PROMETHEUS}', sys.argv[2])
json_str = json_str.replace('${DS_LOKI}', sys.argv[3]) if sys.argv[3]:
json_str = json_str.replace('${DS_LOKI}', sys.argv[3])
dashboard = json.loads(json_str) dashboard = json.loads(json_str)
# Remove Grafana-internal fields # Remove Grafana-internal fields
dashboard.pop('id', None) for key in ('id', 'version', 'iteration'):
dashboard.pop('version', None) dashboard.pop(key, None)
dashboard.pop('iteration', None)
payload = { payload = {
'dashboard': dashboard, 'dashboard': dashboard,
@ -374,8 +378,7 @@ payload = {
} }
print(json.dumps(payload)) print(json.dumps(payload))
PYEOF PYEOF
"$full_path" "$PROMETHEUS_UID" "${LOKI_UID:-}" "$folder_id" 2>/dev/null) )
fi
if [[ -z "$api_payload" ]]; then if [[ -z "$api_payload" ]]; then
error "Failed to process dashboard JSON: ${file}" error "Failed to process dashboard JSON: ${file}"
@ -388,9 +391,10 @@ PYEOF
tmpfile=$(mktemp /tmp/dashboard-payload.XXXXXX) tmpfile=$(mktemp /tmp/dashboard-payload.XXXXXX)
echo "$api_payload" > "$tmpfile" echo "$api_payload" > "$tmpfile"
incus file push "$tmpfile" "${CLUSTER_REMOTE}:${MONITORING_CONTAINER}/tmp/dashboard-payload.json" >/dev/null 2>&1
local result local result
result=$(incus file push "$tmpfile" "${CLUSTER_REMOTE}:${MONITORING_CONTAINER}/tmp/dashboard-payload.json" 2>/dev/null && \ result=$(grafana_api POST "/api/dashboards/db" \
grafana_api POST "/api/dashboards/db" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d @/tmp/dashboard-payload.json 2>/dev/null) -d @/tmp/dashboard-payload.json 2>/dev/null)
rm -f "$tmpfile" rm -f "$tmpfile"
@ -417,7 +421,7 @@ except:
# Clean up temp file in container # Clean up temp file in container
incus exec "${CLUSTER_REMOTE}:${MONITORING_CONTAINER}" -- rm -f /tmp/dashboard-payload.json 2>/dev/null || true incus exec "${CLUSTER_REMOTE}:${MONITORING_CONTAINER}" -- rm -f /tmp/dashboard-payload.json 2>/dev/null || true
done < <(read_manifest) done 3< <(read_manifest)
echo echo
if [[ $failed -eq 0 ]]; then if [[ $failed -eq 0 ]]; then
@ -446,7 +450,7 @@ action_export() {
fi fi
# Export all dashboards listed in the manifest # Export all dashboards listed in the manifest
while IFS=$'\t' read -r file uid title folder category version description; do while IFS=$'\t' read -r file uid title folder category version description <&3; do
if [[ -n "$FILTER_CATEGORY" && "$category" != "$FILTER_CATEGORY" ]]; then if [[ -n "$FILTER_CATEGORY" && "$category" != "$FILTER_CATEGORY" ]]; then
continue continue
fi fi
@ -454,7 +458,7 @@ action_export() {
if export_single_dashboard "$uid" "${DASHBOARDS_DIR}/${file}"; then if export_single_dashboard "$uid" "${DASHBOARDS_DIR}/${file}"; then
exported=$((exported + 1)) exported=$((exported + 1))
fi fi
done < <(read_manifest) done 3< <(read_manifest)
echo echo
success "Exported ${exported} dashboard(s)" success "Exported ${exported} dashboard(s)"
@ -560,7 +564,7 @@ action_list() {
printf " ${BOLD}%-35s %-30s %-20s %s${RESET}\n" "UID" "Title" "Folder" "Status" printf " ${BOLD}%-35s %-30s %-20s %s${RESET}\n" "UID" "Title" "Folder" "Status"
printf " %-35s %-30s %-20s %s\n" "---" "-----" "------" "------" printf " %-35s %-30s %-20s %s\n" "---" "-----" "------" "------"
while IFS=$'\t' read -r file uid title folder category version description; do while IFS=$'\t' read -r file uid title folder category version description <&3; do
if [[ -n "$FILTER_CATEGORY" && "$category" != "$FILTER_CATEGORY" ]]; then if [[ -n "$FILTER_CATEGORY" && "$category" != "$FILTER_CATEGORY" ]]; then
continue continue
fi fi
@ -601,7 +605,7 @@ except:
printf " %-35s %-30s %-20s " "$uid" "$title" "$folder" printf " %-35s %-30s %-20s " "$uid" "$title" "$folder"
echo -e "$status_display" echo -e "$status_display"
done < <(read_manifest) done 3< <(read_manifest)
} }
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@ -617,7 +621,7 @@ action_validate() {
local warnings=0 local warnings=0
local errors=0 local errors=0
while IFS=$'\t' read -r file uid title folder category version description; do while IFS=$'\t' read -r file uid title folder category version description <&3; do
if [[ -n "$FILTER_CATEGORY" && "$category" != "$FILTER_CATEGORY" ]]; then if [[ -n "$FILTER_CATEGORY" && "$category" != "$FILTER_CATEGORY" ]]; then
continue continue
fi fi
@ -734,7 +738,7 @@ PYEOF
success " ${basename_file}: valid" success " ${basename_file}: valid"
fi fi
done < <(read_manifest) done 3< <(read_manifest)
echo echo
info "${total} dashboard(s) checked: ${passed} passed, ${errors} errors, ${warnings} warnings" info "${total} dashboard(s) checked: ${passed} passed, ${errors} errors, ${warnings} warnings"
@ -758,7 +762,7 @@ action_status() {
printf " ${BOLD}%-30s %-15s %-15s %s${RESET}\n" "Dashboard" "Local" "Grafana" "Match" printf " ${BOLD}%-30s %-15s %-15s %s${RESET}\n" "Dashboard" "Local" "Grafana" "Match"
printf " %-30s %-15s %-15s %s\n" "---------" "-----" "-------" "-----" printf " %-30s %-15s %-15s %s\n" "---------" "-----" "-------" "-----"
while IFS=$'\t' read -r file uid title folder category version description; do while IFS=$'\t' read -r file uid title folder category version description <&3; do
local full_path="${DASHBOARDS_DIR}/${file}" local full_path="${DASHBOARDS_DIR}/${file}"
local local_ver="missing" local local_ver="missing"
@ -794,7 +798,7 @@ except:
printf " %-30s %-15s %-15s " "$title" "$local_ver" "$grafana_ver" printf " %-30s %-15s %-15s " "$title" "$local_ver" "$grafana_ver"
echo -e "$match_str" echo -e "$match_str"
done < <(read_manifest) done 3< <(read_manifest)
} }
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,11 +2,18 @@
"uid": "incus-logs-explorer", "uid": "incus-logs-explorer",
"title": "Logs Explorer", "title": "Logs Explorer",
"description": "Log volume over time, full log stream with search, error and warning rates by systemd unit. Datasource: Loki.", "description": "Log volume over time, full log stream with search, error and warning rates by systemd unit. Datasource: Loki.",
"tags": ["incus", "logs", "loki"], "tags": [
"incus",
"logs",
"loki"
],
"timezone": "browser", "timezone": "browser",
"schemaVersion": 39, "schemaVersion": 39,
"refresh": "30s", "refresh": "30s",
"time": { "from": "now-1h", "to": "now" }, "time": {
"from": "now-1h",
"to": "now"
},
"fiscalYearStartMonth": 0, "fiscalYearStartMonth": 0,
"liveNow": false, "liveNow": false,
"editable": true, "editable": true,
@ -17,7 +24,9 @@
"icon": "external link", "icon": "external link",
"includeVars": true, "includeVars": true,
"keepTime": true, "keepTime": true,
"tags": ["incus"], "tags": [
"incus"
],
"targetBlank": false, "targetBlank": false,
"title": "Incus Dashboards", "title": "Incus Dashboards",
"tooltip": "Navigate to other Incus dashboards", "tooltip": "Navigate to other Incus dashboards",
@ -28,42 +37,57 @@
"list": [ "list": [
{ {
"type": "query", "type": "query",
"datasource": { "type": "loki", "uid": "${DS_LOKI}" }, "datasource": {
"type": "loki",
"uid": "${DS_LOKI}"
},
"query": "label_values(job)", "query": "label_values(job)",
"includeAll": true, "includeAll": true,
"multi": true, "multi": true,
"name": "job", "name": "job",
"label": "Job", "label": "Job",
"refresh": 2, "refresh": 2,
"sort": 1 "sort": 1,
"allValue": ".*"
}, },
{ {
"type": "query", "type": "query",
"datasource": { "type": "loki", "uid": "${DS_LOKI}" }, "datasource": {
"type": "loki",
"uid": "${DS_LOKI}"
},
"query": "label_values(host)", "query": "label_values(host)",
"includeAll": true, "includeAll": true,
"multi": true, "multi": true,
"name": "host", "name": "host",
"label": "Host", "label": "Host",
"refresh": 2, "refresh": 2,
"sort": 1 "sort": 1,
"allValue": ".*"
}, },
{ {
"type": "query", "type": "query",
"datasource": { "type": "loki", "uid": "${DS_LOKI}" }, "datasource": {
"type": "loki",
"uid": "${DS_LOKI}"
},
"query": "label_values(unit)", "query": "label_values(unit)",
"includeAll": true, "includeAll": true,
"multi": true, "multi": true,
"name": "unit", "name": "unit",
"label": "Unit", "label": "Unit",
"refresh": 2, "refresh": 2,
"sort": 1 "sort": 1,
"allValue": ".*"
}, },
{ {
"type": "textbox", "type": "textbox",
"name": "search", "name": "search",
"label": "Search", "label": "Search",
"current": { "text": "", "value": "" } "current": {
"text": "",
"value": ""
}
} }
] ]
}, },
@ -71,7 +95,10 @@
"list": [ "list": [
{ {
"builtIn": 1, "builtIn": 1,
"datasource": { "type": "grafana", "uid": "-- Grafana --" }, "datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true, "enable": true,
"hide": true, "hide": true,
"iconColor": "rgba(0, 211, 255, 1)", "iconColor": "rgba(0, 211, 255, 1)",
@ -85,7 +112,12 @@
"type": "row", "type": "row",
"title": "Log Volume", "title": "Log Volume",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 1, "id": 1,
"panels": [] "panels": []
}, },
@ -93,9 +125,17 @@
"type": "timeseries", "type": "timeseries",
"title": "Log Volume Over Time", "title": "Log Volume Over Time",
"description": "Total log line count over time, broken down by job. Shows the rate at which logs are being generated across all selected sources.", "description": "Total log line count over time, broken down by job. Shows the rate at which logs are being generated across all selected sources.",
"gridPos": { "h": 6, "w": 24, "x": 0, "y": 1 }, "gridPos": {
"h": 6,
"w": 24,
"x": 0,
"y": 1
},
"id": 2, "id": 2,
"datasource": { "type": "loki", "uid": "${DS_LOKI}" }, "datasource": {
"type": "loki",
"uid": "${DS_LOKI}"
},
"targets": [ "targets": [
{ {
"expr": "sum by (job) (count_over_time({job=~\"$job\", host=~\"$host\"} [$__auto]))", "expr": "sum by (job) (count_over_time({job=~\"$job\", host=~\"$host\"} [$__auto]))",
@ -114,31 +154,61 @@
"spanNulls": false, "spanNulls": false,
"showPoints": "never", "showPoints": "never",
"pointSize": 5, "pointSize": 5,
"stacking": { "mode": "normal", "group": "A" }, "stacking": {
"mode": "normal",
"group": "A"
},
"axisPlacement": "auto", "axisPlacement": "auto",
"axisLabel": "", "axisLabel": "",
"scaleDistribution": { "type": "linear" }, "scaleDistribution": {
"thresholdsStyle": { "mode": "off" } "type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "short", "unit": "short",
"color": { "mode": "palette-classic" }, "color": {
"mode": "palette-classic"
},
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "green", "value": null }] "steps": [
{
"color": "green",
"value": null
}
]
} }
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["sum", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"sum",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "row", "type": "row",
"title": "Log Stream", "title": "Log Stream",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 7 }, "gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 7
},
"id": 3, "id": 3,
"panels": [] "panels": []
}, },
@ -146,9 +216,17 @@
"type": "logs", "type": "logs",
"title": "Logs", "title": "Logs",
"description": "Live log stream filtered by job, host, unit, and free-text search. Displays timestamps, labels, and full log messages with expand-on-click detail view.", "description": "Live log stream filtered by job, host, unit, and free-text search. Displays timestamps, labels, and full log messages with expand-on-click detail view.",
"gridPos": { "h": 16, "w": 24, "x": 0, "y": 8 }, "gridPos": {
"h": 16,
"w": 24,
"x": 0,
"y": 8
},
"id": 4, "id": 4,
"datasource": { "type": "loki", "uid": "${DS_LOKI}" }, "datasource": {
"type": "loki",
"uid": "${DS_LOKI}"
},
"targets": [ "targets": [
{ {
"expr": "{job=~\"$job\", host=~\"$host\", unit=~\"$unit\"} |= \"$search\"", "expr": "{job=~\"$job\", host=~\"$host\", unit=~\"$unit\"} |= \"$search\"",
@ -170,7 +248,12 @@
"type": "row", "type": "row",
"title": "Error & Warning Rates", "title": "Error & Warning Rates",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 24 }, "gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 24
},
"id": 5, "id": 5,
"panels": [] "panels": []
}, },
@ -178,9 +261,17 @@
"type": "timeseries", "type": "timeseries",
"title": "Error Rate by Unit", "title": "Error Rate by Unit",
"description": "Rate of log lines matching error, fail, or fatal (case-insensitive) over time, grouped by systemd unit. Spikes indicate services experiencing failures.", "description": "Rate of log lines matching error, fail, or fatal (case-insensitive) over time, grouped by systemd unit. Spikes indicate services experiencing failures.",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 25 }, "gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 25
},
"id": 6, "id": 6,
"datasource": { "type": "loki", "uid": "${DS_LOKI}" }, "datasource": {
"type": "loki",
"uid": "${DS_LOKI}"
},
"targets": [ "targets": [
{ {
"expr": "sum by (unit) (count_over_time({job=~\"$job\", host=~\"$host\"} |~ \"(?i)error|fail|fatal\" [$__auto]))", "expr": "sum by (unit) (count_over_time({job=~\"$job\", host=~\"$host\"} |~ \"(?i)error|fail|fatal\" [$__auto]))",
@ -199,33 +290,67 @@
"spanNulls": false, "spanNulls": false,
"showPoints": "never", "showPoints": "never",
"pointSize": 5, "pointSize": 5,
"stacking": { "mode": "none", "group": "A" }, "stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto", "axisPlacement": "auto",
"axisLabel": "", "axisLabel": "",
"scaleDistribution": { "type": "linear" }, "scaleDistribution": {
"thresholdsStyle": { "mode": "off" } "type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "short", "unit": "short",
"color": { "mode": "fixed", "fixedColor": "red" }, "color": {
"mode": "fixed",
"fixedColor": "red"
},
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "red", "value": null }] "steps": [
{
"color": "red",
"value": null
}
]
} }
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["sum", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"sum",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "timeseries", "type": "timeseries",
"title": "Warning Rate by Unit", "title": "Warning Rate by Unit",
"description": "Rate of log lines matching warn (case-insensitive) over time, grouped by systemd unit. Helps identify services generating warnings that may precede errors.", "description": "Rate of log lines matching warn (case-insensitive) over time, grouped by systemd unit. Helps identify services generating warnings that may precede errors.",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 25 }, "gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 25
},
"id": 7, "id": 7,
"datasource": { "type": "loki", "uid": "${DS_LOKI}" }, "datasource": {
"type": "loki",
"uid": "${DS_LOKI}"
},
"targets": [ "targets": [
{ {
"expr": "sum by (unit) (count_over_time({job=~\"$job\", host=~\"$host\"} |~ \"(?i)warn\" [$__auto]))", "expr": "sum by (unit) (count_over_time({job=~\"$job\", host=~\"$host\"} |~ \"(?i)warn\" [$__auto]))",
@ -244,24 +369,50 @@
"spanNulls": false, "spanNulls": false,
"showPoints": "never", "showPoints": "never",
"pointSize": 5, "pointSize": 5,
"stacking": { "mode": "none", "group": "A" }, "stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto", "axisPlacement": "auto",
"axisLabel": "", "axisLabel": "",
"scaleDistribution": { "type": "linear" }, "scaleDistribution": {
"thresholdsStyle": { "mode": "off" } "type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "short", "unit": "short",
"color": { "mode": "fixed", "fixedColor": "yellow" }, "color": {
"mode": "fixed",
"fixedColor": "yellow"
},
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "yellow", "value": null }] "steps": [
{
"color": "yellow",
"value": null
}
]
} }
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["sum", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"sum",
"max",
"lastNotNull"
]
}
} }
} }
] ]

View File

@ -2,11 +2,19 @@
"uid": "incus-network-deep-dive", "uid": "incus-network-deep-dive",
"title": "Network Deep Dive", "title": "Network Deep Dive",
"description": "Per-node and per-device network traffic, instance-level network metrics, receive/transmit errors, and packet drops.", "description": "Per-node and per-device network traffic, instance-level network metrics, receive/transmit errors, and packet drops.",
"tags": ["incus", "incusos", "network", "node-exporter"], "tags": [
"incus",
"incusos",
"network",
"node-exporter"
],
"timezone": "browser", "timezone": "browser",
"schemaVersion": 39, "schemaVersion": 39,
"refresh": "30s", "refresh": "30s",
"time": { "from": "now-1h", "to": "now" }, "time": {
"from": "now-1h",
"to": "now"
},
"fiscalYearStartMonth": 0, "fiscalYearStartMonth": 0,
"liveNow": false, "liveNow": false,
"editable": true, "editable": true,
@ -17,7 +25,9 @@
"icon": "external link", "icon": "external link",
"includeVars": true, "includeVars": true,
"keepTime": true, "keepTime": true,
"tags": ["incus"], "tags": [
"incus"
],
"targetBlank": false, "targetBlank": false,
"title": "Incus Dashboards", "title": "Incus Dashboards",
"tooltip": "Navigate to other Incus dashboards", "tooltip": "Navigate to other Incus dashboards",
@ -28,7 +38,10 @@
"list": [ "list": [
{ {
"current": {}, "current": {},
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(node_network_receive_bytes_total, instance)", "definition": "label_values(node_network_receive_bytes_total, instance)",
"includeAll": false, "includeAll": false,
"multi": true, "multi": true,
@ -41,7 +54,10 @@
}, },
{ {
"current": {}, "current": {},
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(node_network_receive_bytes_total{instance=~\"$node\"}, device)", "definition": "label_values(node_network_receive_bytes_total{instance=~\"$node\"}, device)",
"includeAll": true, "includeAll": true,
"multi": true, "multi": true,
@ -51,7 +67,8 @@
"regex": "/^(?!lo$).*/", "regex": "/^(?!lo$).*/",
"sort": 1, "sort": 1,
"type": "query", "type": "query",
"label": "Device" "label": "Device",
"allValue": ".*"
} }
] ]
}, },
@ -59,7 +76,10 @@
"list": [ "list": [
{ {
"builtIn": 1, "builtIn": 1,
"datasource": { "type": "grafana", "uid": "-- Grafana --" }, "datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true, "enable": true,
"hide": true, "hide": true,
"iconColor": "rgba(0, 211, 255, 1)", "iconColor": "rgba(0, 211, 255, 1)",
@ -73,7 +93,12 @@
"type": "row", "type": "row",
"title": "Cluster Summary", "title": "Cluster Summary",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 1, "id": 1,
"panels": [] "panels": []
}, },
@ -81,9 +106,17 @@
"type": "stat", "type": "stat",
"title": "Total Ingress", "title": "Total Ingress",
"description": "Aggregate inbound network throughput across all selected nodes and devices.", "description": "Aggregate inbound network throughput across all selected nodes and devices.",
"gridPos": { "h": 4, "w": 6, "x": 0, "y": 1 }, "gridPos": {
"h": 4,
"w": 6,
"x": 0,
"y": 1
},
"id": 2, "id": 2,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "sum(rate(node_network_receive_bytes_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval]))", "expr": "sum(rate(node_network_receive_bytes_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval]))",
@ -95,15 +128,28 @@
"defaults": { "defaults": {
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "green", "value": null }] "steps": [
{
"color": "green",
"value": null
}
]
}, },
"unit": "Bps", "unit": "Bps",
"color": { "mode": "thresholds" } "color": {
"mode": "thresholds"
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"orientation": "auto", "orientation": "auto",
"textMode": "auto", "textMode": "auto",
"colorMode": "value", "colorMode": "value",
@ -115,9 +161,17 @@
"type": "stat", "type": "stat",
"title": "Total Egress", "title": "Total Egress",
"description": "Aggregate outbound network throughput across all selected nodes and devices.", "description": "Aggregate outbound network throughput across all selected nodes and devices.",
"gridPos": { "h": 4, "w": 6, "x": 6, "y": 1 }, "gridPos": {
"h": 4,
"w": 6,
"x": 6,
"y": 1
},
"id": 3, "id": 3,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "sum(rate(node_network_transmit_bytes_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval]))", "expr": "sum(rate(node_network_transmit_bytes_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval]))",
@ -129,15 +183,28 @@
"defaults": { "defaults": {
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "green", "value": null }] "steps": [
{
"color": "green",
"value": null
}
]
}, },
"unit": "Bps", "unit": "Bps",
"color": { "mode": "thresholds" } "color": {
"mode": "thresholds"
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"orientation": "auto", "orientation": "auto",
"textMode": "auto", "textMode": "auto",
"colorMode": "value", "colorMode": "value",
@ -149,9 +216,17 @@
"type": "stat", "type": "stat",
"title": "Total Errors", "title": "Total Errors",
"description": "Combined receive and transmit error rate across all selected nodes. Any non-zero value warrants investigation.", "description": "Combined receive and transmit error rate across all selected nodes. Any non-zero value warrants investigation.",
"gridPos": { "h": 4, "w": 6, "x": 12, "y": 1 }, "gridPos": {
"h": 4,
"w": 6,
"x": 12,
"y": 1
},
"id": 4, "id": 4,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "sum(rate(node_network_receive_errs_total{instance=~\"$node\"}[$__rate_interval])) + sum(rate(node_network_transmit_errs_total{instance=~\"$node\"}[$__rate_interval]))", "expr": "sum(rate(node_network_receive_errs_total{instance=~\"$node\"}[$__rate_interval])) + sum(rate(node_network_transmit_errs_total{instance=~\"$node\"}[$__rate_interval]))",
@ -164,18 +239,35 @@
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [
{ "color": "green", "value": null }, {
{ "color": "yellow", "value": 0.1 }, "color": "green",
{ "color": "red", "value": 1 } "value": null
},
{
"color": "yellow",
"value": 0.1
},
{
"color": "red",
"value": 1
}
] ]
}, },
"unit": "pps", "unit": "pps",
"color": { "mode": "thresholds" } "color": {
"mode": "thresholds"
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"orientation": "auto", "orientation": "auto",
"textMode": "auto", "textMode": "auto",
"colorMode": "value", "colorMode": "value",
@ -187,9 +279,17 @@
"type": "stat", "type": "stat",
"title": "Total Drops", "title": "Total Drops",
"description": "Combined receive and transmit packet drop rate across all selected nodes. Drops indicate buffer or queue exhaustion.", "description": "Combined receive and transmit packet drop rate across all selected nodes. Drops indicate buffer or queue exhaustion.",
"gridPos": { "h": 4, "w": 6, "x": 18, "y": 1 }, "gridPos": {
"h": 4,
"w": 6,
"x": 18,
"y": 1
},
"id": 5, "id": 5,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "sum(rate(node_network_receive_drop_total{instance=~\"$node\"}[$__rate_interval])) + sum(rate(node_network_transmit_drop_total{instance=~\"$node\"}[$__rate_interval]))", "expr": "sum(rate(node_network_receive_drop_total{instance=~\"$node\"}[$__rate_interval])) + sum(rate(node_network_transmit_drop_total{instance=~\"$node\"}[$__rate_interval]))",
@ -202,18 +302,35 @@
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [
{ "color": "green", "value": null }, {
{ "color": "yellow", "value": 0.1 }, "color": "green",
{ "color": "red", "value": 1 } "value": null
},
{
"color": "yellow",
"value": 0.1
},
{
"color": "red",
"value": 1
}
] ]
}, },
"unit": "pps", "unit": "pps",
"color": { "mode": "thresholds" } "color": {
"mode": "thresholds"
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"orientation": "auto", "orientation": "auto",
"textMode": "auto", "textMode": "auto",
"colorMode": "value", "colorMode": "value",
@ -225,7 +342,12 @@
"type": "row", "type": "row",
"title": "Per-Node Traffic", "title": "Per-Node Traffic",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 5 }, "gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 5
},
"id": 10, "id": 10,
"panels": [] "panels": []
}, },
@ -233,9 +355,17 @@
"type": "timeseries", "type": "timeseries",
"title": "Receive Rate by Node & Device", "title": "Receive Rate by Node & Device",
"description": "Inbound network throughput broken down by node and network device. Identifies which interfaces are handling the most receive traffic.", "description": "Inbound network throughput broken down by node and network device. Identifies which interfaces are handling the most receive traffic.",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 6 }, "gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 6
},
"id": 11, "id": 11,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "rate(node_network_receive_bytes_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval])", "expr": "rate(node_network_receive_bytes_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval])",
@ -254,33 +384,66 @@
"spanNulls": false, "spanNulls": false,
"showPoints": "never", "showPoints": "never",
"pointSize": 5, "pointSize": 5,
"stacking": { "mode": "none", "group": "A" }, "stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto", "axisPlacement": "auto",
"axisLabel": "", "axisLabel": "",
"scaleDistribution": { "type": "linear" }, "scaleDistribution": {
"thresholdsStyle": { "mode": "off" } "type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "Bps", "unit": "Bps",
"color": { "mode": "palette-classic" }, "color": {
"mode": "palette-classic"
},
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "green", "value": null }] "steps": [
{
"color": "green",
"value": null
}
]
} }
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "timeseries", "type": "timeseries",
"title": "Transmit Rate by Node & Device", "title": "Transmit Rate by Node & Device",
"description": "Outbound network throughput broken down by node and network device. Identifies which interfaces are handling the most transmit traffic.", "description": "Outbound network throughput broken down by node and network device. Identifies which interfaces are handling the most transmit traffic.",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 6 }, "gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 6
},
"id": 12, "id": 12,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "rate(node_network_transmit_bytes_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval])", "expr": "rate(node_network_transmit_bytes_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval])",
@ -299,31 +462,61 @@
"spanNulls": false, "spanNulls": false,
"showPoints": "never", "showPoints": "never",
"pointSize": 5, "pointSize": 5,
"stacking": { "mode": "none", "group": "A" }, "stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto", "axisPlacement": "auto",
"axisLabel": "", "axisLabel": "",
"scaleDistribution": { "type": "linear" }, "scaleDistribution": {
"thresholdsStyle": { "mode": "off" } "type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "Bps", "unit": "Bps",
"color": { "mode": "palette-classic" }, "color": {
"mode": "palette-classic"
},
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "green", "value": null }] "steps": [
{
"color": "green",
"value": null
}
]
} }
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "row", "type": "row",
"title": "Instance Network (Incus metrics)", "title": "Instance Network (Incus metrics)",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 14 }, "gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 14
},
"id": 20, "id": 20,
"panels": [] "panels": []
}, },
@ -331,9 +524,17 @@
"type": "timeseries", "type": "timeseries",
"title": "Instance Receive Rate", "title": "Instance Receive Rate",
"description": "Inbound network throughput per Incus instance, aggregated across all instance network devices. Uses Incus-native metrics for container and VM visibility.", "description": "Inbound network throughput per Incus instance, aggregated across all instance network devices. Uses Incus-native metrics for container and VM visibility.",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 15 }, "gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 15
},
"id": 21, "id": 21,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "sum by (name) (rate(incus_network_receive_bytes_total{instance=~\"$node\"}[$__rate_interval]))", "expr": "sum by (name) (rate(incus_network_receive_bytes_total{instance=~\"$node\"}[$__rate_interval]))",
@ -352,33 +553,66 @@
"spanNulls": false, "spanNulls": false,
"showPoints": "never", "showPoints": "never",
"pointSize": 5, "pointSize": 5,
"stacking": { "mode": "none", "group": "A" }, "stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto", "axisPlacement": "auto",
"axisLabel": "", "axisLabel": "",
"scaleDistribution": { "type": "linear" }, "scaleDistribution": {
"thresholdsStyle": { "mode": "off" } "type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "Bps", "unit": "Bps",
"color": { "mode": "palette-classic" }, "color": {
"mode": "palette-classic"
},
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "green", "value": null }] "steps": [
{
"color": "green",
"value": null
}
]
} }
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "timeseries", "type": "timeseries",
"title": "Instance Transmit Rate", "title": "Instance Transmit Rate",
"description": "Outbound network throughput per Incus instance, aggregated across all instance network devices. Uses Incus-native metrics for container and VM visibility.", "description": "Outbound network throughput per Incus instance, aggregated across all instance network devices. Uses Incus-native metrics for container and VM visibility.",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 15 }, "gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 15
},
"id": 22, "id": 22,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "sum by (name) (rate(incus_network_transmit_bytes_total{instance=~\"$node\"}[$__rate_interval]))", "expr": "sum by (name) (rate(incus_network_transmit_bytes_total{instance=~\"$node\"}[$__rate_interval]))",
@ -397,31 +631,61 @@
"spanNulls": false, "spanNulls": false,
"showPoints": "never", "showPoints": "never",
"pointSize": 5, "pointSize": 5,
"stacking": { "mode": "none", "group": "A" }, "stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto", "axisPlacement": "auto",
"axisLabel": "", "axisLabel": "",
"scaleDistribution": { "type": "linear" }, "scaleDistribution": {
"thresholdsStyle": { "mode": "off" } "type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "Bps", "unit": "Bps",
"color": { "mode": "palette-classic" }, "color": {
"mode": "palette-classic"
},
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "green", "value": null }] "steps": [
{
"color": "green",
"value": null
}
]
} }
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "row", "type": "row",
"title": "Errors & Drops", "title": "Errors & Drops",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 23 }, "gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 23
},
"id": 30, "id": 30,
"panels": [] "panels": []
}, },
@ -429,9 +693,17 @@
"type": "timeseries", "type": "timeseries",
"title": "Receive/Transmit Errors", "title": "Receive/Transmit Errors",
"description": "Network interface error rates broken down by node and device. Receive errors may indicate CRC failures or framing issues; transmit errors may indicate collisions or driver problems.", "description": "Network interface error rates broken down by node and device. Receive errors may indicate CRC failures or framing issues; transmit errors may indicate collisions or driver problems.",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 24 }, "gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 24
},
"id": 31, "id": 31,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "rate(node_network_receive_errs_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval])", "expr": "rate(node_network_receive_errs_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval])",
@ -455,33 +727,66 @@
"spanNulls": false, "spanNulls": false,
"showPoints": "never", "showPoints": "never",
"pointSize": 5, "pointSize": 5,
"stacking": { "mode": "none", "group": "A" }, "stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto", "axisPlacement": "auto",
"axisLabel": "", "axisLabel": "",
"scaleDistribution": { "type": "linear" }, "scaleDistribution": {
"thresholdsStyle": { "mode": "off" } "type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "pps", "unit": "pps",
"color": { "mode": "palette-classic" }, "color": {
"mode": "palette-classic"
},
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "green", "value": null }] "steps": [
{
"color": "green",
"value": null
}
]
} }
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "timeseries", "type": "timeseries",
"title": "Packet Drops", "title": "Packet Drops",
"description": "Network interface packet drop rates broken down by node and device. Drops indicate kernel buffer or queue exhaustion and may cause retransmissions or connection failures.", "description": "Network interface packet drop rates broken down by node and device. Drops indicate kernel buffer or queue exhaustion and may cause retransmissions or connection failures.",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 24 }, "gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 24
},
"id": 32, "id": 32,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "rate(node_network_receive_drop_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval])", "expr": "rate(node_network_receive_drop_total{instance=~\"$node\", device=~\"$device\"}[$__rate_interval])",
@ -505,24 +810,49 @@
"spanNulls": false, "spanNulls": false,
"showPoints": "never", "showPoints": "never",
"pointSize": 5, "pointSize": 5,
"stacking": { "mode": "none", "group": "A" }, "stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto", "axisPlacement": "auto",
"axisLabel": "", "axisLabel": "",
"scaleDistribution": { "type": "linear" }, "scaleDistribution": {
"thresholdsStyle": { "mode": "off" } "type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "pps", "unit": "pps",
"color": { "mode": "palette-classic" }, "color": {
"mode": "palette-classic"
},
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [{ "color": "green", "value": null }] "steps": [
{
"color": "green",
"value": null
}
]
} }
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
} }
] ]

View File

@ -2,27 +2,45 @@
"uid": "incus-storage-filesystem", "uid": "incus-storage-filesystem",
"title": "Storage & Filesystem", "title": "Storage & Filesystem",
"description": "Filesystem usage, available space trends, disk throughput, I/O latency, disk utilization, and inode usage per node.", "description": "Filesystem usage, available space trends, disk throughput, I/O latency, disk utilization, and inode usage per node.",
"tags": ["incus", "incusos", "storage", "node-exporter"], "tags": [
"incus",
"incusos",
"storage",
"node-exporter"
],
"timezone": "browser", "timezone": "browser",
"schemaVersion": 39, "schemaVersion": 39,
"refresh": "30s", "refresh": "30s",
"time": { "from": "now-1h", "to": "now" }, "time": {
"from": "now-1h",
"to": "now"
},
"fiscalYearStartMonth": 0, "fiscalYearStartMonth": 0,
"liveNow": false, "liveNow": false,
"editable": true, "editable": true,
"graphTooltip": 1, "graphTooltip": 1,
"links": [ "links": [
{ {
"asDropdown": true, "icon": "external link", "includeVars": true, "asDropdown": true,
"keepTime": true, "tags": ["incus"], "targetBlank": false, "icon": "external link",
"title": "Incus Dashboards", "type": "dashboards" "includeVars": true,
"keepTime": true,
"tags": [
"incus"
],
"targetBlank": false,
"title": "Incus Dashboards",
"type": "dashboards"
} }
], ],
"templating": { "templating": {
"list": [ "list": [
{ {
"current": {}, "current": {},
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(node_filesystem_size_bytes, instance)", "definition": "label_values(node_filesystem_size_bytes, instance)",
"includeAll": false, "includeAll": false,
"multi": true, "multi": true,
@ -35,7 +53,10 @@
}, },
{ {
"current": {}, "current": {},
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(node_filesystem_size_bytes{instance=~\"$node\"}, mountpoint)", "definition": "label_values(node_filesystem_size_bytes{instance=~\"$node\"}, mountpoint)",
"includeAll": true, "includeAll": true,
"multi": true, "multi": true,
@ -44,7 +65,8 @@
"refresh": 2, "refresh": 2,
"sort": 1, "sort": 1,
"type": "query", "type": "query",
"label": "Mountpoint" "label": "Mountpoint",
"allValue": ".*"
} }
] ]
}, },
@ -52,83 +74,264 @@
"list": [ "list": [
{ {
"builtIn": 1, "builtIn": 1,
"datasource": { "type": "grafana", "uid": "-- Grafana --" }, "datasource": {
"enable": true, "hide": true, "type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)", "iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts", "type": "dashboard" "name": "Annotations & Alerts",
"type": "dashboard"
} }
] ]
}, },
"panels": [ "panels": [
{ {
"type": "row", "title": "Filesystem Overview", "type": "row",
"title": "Filesystem Overview",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "gridPos": {
"id": 1, "panels": [] "h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 1,
"panels": []
}, },
{ {
"type": "table", "type": "table",
"title": "Filesystem Usage Table", "title": "Filesystem Usage Table",
"description": "Current filesystem size, available space, and usage percentage per node and mountpoint. High usage is highlighted with color thresholds.", "description": "Current filesystem size, available space, and usage percentage per node and mountpoint. High usage is highlighted with color thresholds.",
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 1 }, "gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 1
},
"id": 2, "id": 2,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "node_filesystem_size_bytes{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"}", "expr": "node_filesystem_size_bytes{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"}",
"legendFormat": "", "refId": "A", "format": "table", "instant": true "legendFormat": "",
"refId": "A",
"format": "table",
"instant": true
}, },
{ {
"expr": "node_filesystem_avail_bytes{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"}", "expr": "node_filesystem_avail_bytes{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"}",
"legendFormat": "", "refId": "B", "format": "table", "instant": true "legendFormat": "",
"refId": "B",
"format": "table",
"instant": true
}, },
{ {
"expr": "(1 - node_filesystem_avail_bytes{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"} / node_filesystem_size_bytes{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"}) * 100", "expr": "(1 - node_filesystem_avail_bytes{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"} / node_filesystem_size_bytes{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"}) * 100",
"legendFormat": "", "refId": "C", "format": "table", "instant": true "legendFormat": "",
"refId": "C",
"format": "table",
"instant": true
} }
], ],
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"custom": { "align": "auto", "displayMode": "auto", "inspect": false, "filterable": true }, "custom": {
"color": { "mode": "thresholds" }, "align": "auto",
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] } "displayMode": "auto",
"inspect": false,
"filterable": true
},
"color": {
"mode": "thresholds"
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
}, },
"overrides": [ "overrides": [
{ "matcher": { "id": "byName", "options": "instance" }, "properties": [{ "id": "displayName", "value": "Node" }] },
{ "matcher": { "id": "byName", "options": "mountpoint" }, "properties": [{ "id": "displayName", "value": "Mountpoint" }] },
{ "matcher": { "id": "byName", "options": "fstype" }, "properties": [{ "id": "displayName", "value": "FS Type" }] },
{ "matcher": { "id": "byName", "options": "Value #A" }, "properties": [{ "id": "displayName", "value": "Size" }, { "id": "unit", "value": "bytes" }] },
{ "matcher": { "id": "byName", "options": "Value #B" }, "properties": [{ "id": "displayName", "value": "Available" }, { "id": "unit", "value": "bytes" }] },
{ {
"matcher": { "id": "byName", "options": "Value #C" }, "matcher": {
"id": "byName",
"options": "instance"
},
"properties": [ "properties": [
{ "id": "displayName", "value": "Used %" }, {
{ "id": "unit", "value": "percent" }, "id": "displayName",
{ "id": "custom.displayMode", "value": "color-background" }, "value": "Node"
{ "id": "thresholds", "value": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "yellow", "value": 70 }, { "color": "orange", "value": 85 }, { "color": "red", "value": 95 }] } } }
]
},
{
"matcher": {
"id": "byName",
"options": "mountpoint"
},
"properties": [
{
"id": "displayName",
"value": "Mountpoint"
}
]
},
{
"matcher": {
"id": "byName",
"options": "fstype"
},
"properties": [
{
"id": "displayName",
"value": "FS Type"
}
]
},
{
"matcher": {
"id": "byName",
"options": "Value #A"
},
"properties": [
{
"id": "displayName",
"value": "Size"
},
{
"id": "unit",
"value": "bytes"
}
]
},
{
"matcher": {
"id": "byName",
"options": "Value #B"
},
"properties": [
{
"id": "displayName",
"value": "Available"
},
{
"id": "unit",
"value": "bytes"
}
]
},
{
"matcher": {
"id": "byName",
"options": "Value #C"
},
"properties": [
{
"id": "displayName",
"value": "Used %"
},
{
"id": "unit",
"value": "percent"
},
{
"id": "custom.displayMode",
"value": "color-background"
},
{
"id": "thresholds",
"value": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "yellow",
"value": 70
},
{
"color": "orange",
"value": 85
},
{
"color": "red",
"value": 95
}
]
}
}
] ]
} }
] ]
}, },
"options": { "showHeader": true, "sortBy": [], "footer": { "show": false, "reducer": ["sum"], "fields": "" } }, "options": {
"showHeader": true,
"sortBy": [],
"footer": {
"show": false,
"reducer": [
"sum"
],
"fields": ""
}
},
"transformations": [ "transformations": [
{ "id": "merge", "options": {} }, {
{ "id": "organize", "options": { "excludeByName": { "Time": true, "__name__": true, "job": true, "device": true }, "renameByName": {} } } "id": "merge",
"options": {}
},
{
"id": "organize",
"options": {
"excludeByName": {
"Time": true,
"__name__": true,
"job": true,
"device": true
},
"renameByName": {}
}
}
] ]
}, },
{ {
"type": "row", "title": "Space Trends", "type": "row",
"title": "Space Trends",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 9 }, "gridPos": {
"id": 3, "panels": [] "h": 1,
"w": 24,
"x": 0,
"y": 9
},
"id": 3,
"panels": []
}, },
{ {
"type": "timeseries", "type": "timeseries",
"title": "Available Space Over Time", "title": "Available Space Over Time",
"description": "Tracks available filesystem space over time per node and mountpoint. Use this to identify gradual space consumption trends before they become critical.", "description": "Tracks available filesystem space over time per node and mountpoint. Use this to identify gradual space consumption trends before they become critical.",
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 10 }, "gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 10
},
"id": 4, "id": 4,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "node_filesystem_avail_bytes{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"}", "expr": "node_filesystem_avail_bytes{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"}",
@ -139,37 +342,86 @@
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"custom": { "custom": {
"drawStyle": "line", "lineInterpolation": "smooth", "lineWidth": 2, "drawStyle": "line",
"fillOpacity": 15, "gradientMode": "none", "spanNulls": false, "lineInterpolation": "smooth",
"showPoints": "never", "pointSize": 5, "lineWidth": 2,
"stacking": { "mode": "none", "group": "A" }, "fillOpacity": 15,
"axisPlacement": "auto", "scaleDistribution": { "type": "linear" }, "gradientMode": "none",
"thresholdsStyle": { "mode": "off" } "spanNulls": false,
"showPoints": "never",
"pointSize": 5,
"stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto",
"scaleDistribution": {
"type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "bytes", "unit": "bytes",
"color": { "mode": "palette-classic" }, "color": {
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] } "mode": "palette-classic"
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "row", "title": "Disk Throughput", "type": "row",
"title": "Disk Throughput",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 18 }, "gridPos": {
"id": 5, "panels": [] "h": 1,
"w": 24,
"x": 0,
"y": 18
},
"id": 5,
"panels": []
}, },
{ {
"type": "timeseries", "type": "timeseries",
"title": "Disk Read Throughput", "title": "Disk Read Throughput",
"description": "Disk read throughput in bytes per second, broken down by instance and device. Identifies which disks are handling the most read traffic.", "description": "Disk read throughput in bytes per second, broken down by instance and device. Identifies which disks are handling the most read traffic.",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 19 }, "gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 19
},
"id": 6, "id": 6,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "sum by (instance, device) (rate(node_disk_read_bytes_total{instance=~\"$node\"}[$__rate_interval]))", "expr": "sum by (instance, device) (rate(node_disk_read_bytes_total{instance=~\"$node\"}[$__rate_interval]))",
@ -180,31 +432,73 @@
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"custom": { "custom": {
"drawStyle": "line", "lineInterpolation": "smooth", "lineWidth": 1, "drawStyle": "line",
"fillOpacity": 15, "gradientMode": "none", "spanNulls": false, "lineInterpolation": "smooth",
"showPoints": "never", "pointSize": 5, "lineWidth": 1,
"stacking": { "mode": "none", "group": "A" }, "fillOpacity": 15,
"axisPlacement": "auto", "scaleDistribution": { "type": "linear" }, "gradientMode": "none",
"thresholdsStyle": { "mode": "off" } "spanNulls": false,
"showPoints": "never",
"pointSize": 5,
"stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto",
"scaleDistribution": {
"type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "Bps", "unit": "Bps",
"color": { "mode": "palette-classic" }, "color": {
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] } "mode": "palette-classic"
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "timeseries", "type": "timeseries",
"title": "Disk Write Throughput", "title": "Disk Write Throughput",
"description": "Disk write throughput in bytes per second, broken down by instance and device. Identifies which disks are handling the most write traffic.", "description": "Disk write throughput in bytes per second, broken down by instance and device. Identifies which disks are handling the most write traffic.",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 19 }, "gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 19
},
"id": 7, "id": 7,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "sum by (instance, device) (rate(node_disk_written_bytes_total{instance=~\"$node\"}[$__rate_interval]))", "expr": "sum by (instance, device) (rate(node_disk_written_bytes_total{instance=~\"$node\"}[$__rate_interval]))",
@ -215,37 +509,86 @@
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"custom": { "custom": {
"drawStyle": "line", "lineInterpolation": "smooth", "lineWidth": 1, "drawStyle": "line",
"fillOpacity": 15, "gradientMode": "none", "spanNulls": false, "lineInterpolation": "smooth",
"showPoints": "never", "pointSize": 5, "lineWidth": 1,
"stacking": { "mode": "none", "group": "A" }, "fillOpacity": 15,
"axisPlacement": "auto", "scaleDistribution": { "type": "linear" }, "gradientMode": "none",
"thresholdsStyle": { "mode": "off" } "spanNulls": false,
"showPoints": "never",
"pointSize": 5,
"stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto",
"scaleDistribution": {
"type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "Bps", "unit": "Bps",
"color": { "mode": "palette-classic" }, "color": {
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] } "mode": "palette-classic"
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "row", "title": "I/O Performance", "type": "row",
"title": "I/O Performance",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 27 }, "gridPos": {
"id": 8, "panels": [] "h": 1,
"w": 24,
"x": 0,
"y": 27
},
"id": 8,
"panels": []
}, },
{ {
"type": "timeseries", "type": "timeseries",
"title": "Average Read Latency", "title": "Average Read Latency",
"description": "Average time per completed read operation. Calculated as total read time divided by completed reads. High values indicate slow disk response.", "description": "Average time per completed read operation. Calculated as total read time divided by completed reads. High values indicate slow disk response.",
"gridPos": { "h": 8, "w": 8, "x": 0, "y": 28 }, "gridPos": {
"h": 8,
"w": 8,
"x": 0,
"y": 28
},
"id": 9, "id": 9,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "rate(node_disk_read_time_seconds_total{instance=~\"$node\"}[$__rate_interval]) / rate(node_disk_reads_completed_total{instance=~\"$node\"}[$__rate_interval])", "expr": "rate(node_disk_read_time_seconds_total{instance=~\"$node\"}[$__rate_interval]) / rate(node_disk_reads_completed_total{instance=~\"$node\"}[$__rate_interval])",
@ -256,31 +599,73 @@
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"custom": { "custom": {
"drawStyle": "line", "lineInterpolation": "smooth", "lineWidth": 1, "drawStyle": "line",
"fillOpacity": 15, "gradientMode": "none", "spanNulls": false, "lineInterpolation": "smooth",
"showPoints": "never", "pointSize": 5, "lineWidth": 1,
"stacking": { "mode": "none", "group": "A" }, "fillOpacity": 15,
"axisPlacement": "auto", "scaleDistribution": { "type": "linear" }, "gradientMode": "none",
"thresholdsStyle": { "mode": "off" } "spanNulls": false,
"showPoints": "never",
"pointSize": 5,
"stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto",
"scaleDistribution": {
"type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "s", "unit": "s",
"color": { "mode": "palette-classic" }, "color": {
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] } "mode": "palette-classic"
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "timeseries", "type": "timeseries",
"title": "Average Write Latency", "title": "Average Write Latency",
"description": "Average time per completed write operation. Calculated as total write time divided by completed writes. High values indicate slow disk response or write saturation.", "description": "Average time per completed write operation. Calculated as total write time divided by completed writes. High values indicate slow disk response or write saturation.",
"gridPos": { "h": 8, "w": 8, "x": 8, "y": 28 }, "gridPos": {
"h": 8,
"w": 8,
"x": 8,
"y": 28
},
"id": 10, "id": 10,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "rate(node_disk_write_time_seconds_total{instance=~\"$node\"}[$__rate_interval]) / rate(node_disk_writes_completed_total{instance=~\"$node\"}[$__rate_interval])", "expr": "rate(node_disk_write_time_seconds_total{instance=~\"$node\"}[$__rate_interval]) / rate(node_disk_writes_completed_total{instance=~\"$node\"}[$__rate_interval])",
@ -291,31 +676,73 @@
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"custom": { "custom": {
"drawStyle": "line", "lineInterpolation": "smooth", "lineWidth": 1, "drawStyle": "line",
"fillOpacity": 15, "gradientMode": "none", "spanNulls": false, "lineInterpolation": "smooth",
"showPoints": "never", "pointSize": 5, "lineWidth": 1,
"stacking": { "mode": "none", "group": "A" }, "fillOpacity": 15,
"axisPlacement": "auto", "scaleDistribution": { "type": "linear" }, "gradientMode": "none",
"thresholdsStyle": { "mode": "off" } "spanNulls": false,
"showPoints": "never",
"pointSize": 5,
"stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto",
"scaleDistribution": {
"type": "linear"
},
"thresholdsStyle": {
"mode": "off"
}
}, },
"unit": "s", "unit": "s",
"color": { "mode": "palette-classic" }, "color": {
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] } "mode": "palette-classic"
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "timeseries", "type": "timeseries",
"title": "Disk Utilization %", "title": "Disk Utilization %",
"description": "Percentage of time the disk is busy processing I/O requests. Values near 100% indicate the disk is saturated and may be a bottleneck.", "description": "Percentage of time the disk is busy processing I/O requests. Values near 100% indicate the disk is saturated and may be a bottleneck.",
"gridPos": { "h": 8, "w": 8, "x": 16, "y": 28 }, "gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 28
},
"id": 11, "id": 11,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "sum by (instance) (rate(node_disk_io_time_seconds_total{instance=~\"$node\"}[$__rate_interval])) * 100", "expr": "sum by (instance) (rate(node_disk_io_time_seconds_total{instance=~\"$node\"}[$__rate_interval])) * 100",
@ -326,37 +753,96 @@
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"custom": { "custom": {
"drawStyle": "line", "lineInterpolation": "smooth", "lineWidth": 2, "drawStyle": "line",
"fillOpacity": 25, "gradientMode": "scheme", "spanNulls": false, "lineInterpolation": "smooth",
"showPoints": "never", "pointSize": 5, "lineWidth": 2,
"stacking": { "mode": "none", "group": "A" }, "fillOpacity": 25,
"axisPlacement": "auto", "scaleDistribution": { "type": "linear" }, "gradientMode": "scheme",
"thresholdsStyle": { "mode": "line" } "spanNulls": false,
"showPoints": "never",
"pointSize": 5,
"stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto",
"scaleDistribution": {
"type": "linear"
},
"thresholdsStyle": {
"mode": "line"
}
}, },
"unit": "percent", "min": 0, "max": 100, "unit": "percent",
"color": { "mode": "continuous-GrYlRd" }, "min": 0,
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "yellow", "value": 50 }, { "color": "red", "value": 80 }] } "max": 100,
"color": {
"mode": "continuous-GrYlRd"
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "yellow",
"value": 50
},
{
"color": "red",
"value": 80
}
]
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"tooltip": { "mode": "multi", "sort": "desc" }, "tooltip": {
"legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max", "lastNotNull"] } "mode": "multi",
"sort": "desc"
},
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": [
"mean",
"max",
"lastNotNull"
]
}
} }
}, },
{ {
"type": "row", "title": "Inodes", "type": "row",
"title": "Inodes",
"collapsed": false, "collapsed": false,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 36 }, "gridPos": {
"id": 12, "panels": [] "h": 1,
"w": 24,
"x": 0,
"y": 36
},
"id": 12,
"panels": []
}, },
{ {
"type": "bargauge", "type": "bargauge",
"title": "Inode Usage %", "title": "Inode Usage %",
"description": "Percentage of used inodes per filesystem. Running out of inodes prevents creating new files even when disk space is available. Monitor for filesystems with many small files.", "description": "Percentage of used inodes per filesystem. Running out of inodes prevents creating new files even when disk space is available. Monitor for filesystems with many small files.",
"gridPos": { "h": 6, "w": 24, "x": 0, "y": 37 }, "gridPos": {
"h": 6,
"w": 24,
"x": 0,
"y": 37
},
"id": 13, "id": 13,
"datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"targets": [ "targets": [
{ {
"expr": "(1 - node_filesystem_files_free{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"} / node_filesystem_files{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"}) * 100", "expr": "(1 - node_filesystem_files_free{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"} / node_filesystem_files{instance=~\"$node\", mountpoint=~\"$mountpoint\", fstype!~\"tmpfs|overlay\"}) * 100",
@ -366,16 +852,46 @@
], ],
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "yellow", "value": 70 }, { "color": "red", "value": 90 }] }, "thresholds": {
"unit": "percent", "min": 0, "max": 100, "mode": "absolute",
"color": { "mode": "thresholds" } "steps": [
{
"color": "green",
"value": null
},
{
"color": "yellow",
"value": 70
},
{
"color": "red",
"value": 90
}
]
},
"unit": "percent",
"min": 0,
"max": 100,
"color": {
"mode": "thresholds"
}
}, },
"overrides": [] "overrides": []
}, },
"options": { "options": {
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "reduceOptions": {
"orientation": "horizontal", "displayMode": "gradient", "showUnfilled": true, "calcs": [
"minVizWidth": 8, "minVizHeight": 16, "valueMode": "color" "lastNotNull"
],
"fields": "",
"values": false
},
"orientation": "horizontal",
"displayMode": "gradient",
"showUnfilled": true,
"minVizWidth": 8,
"minVizHeight": 16,
"valueMode": "color"
} }
} }
] ]

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB