sam 233dadbb41 Add ExaBGP route injector, Grafana dashboards, and full documentation
- Add exabgp/ container: ExaBGP 5.x + Flask REST API for on-demand BGP
  route injection into CML IOS-XR lab (AS 65020 via eBGP from AS 65100)
- Add 6 injection scenarios: internet_sample, churn, blackhole, anycast,
  full_table, lab_prefixes
- Add inject.py CLI wrapper for the ExaBGP API
- Add iosxr_bgp_config.md with IOS-XR neighbor config and NETCONF script
- Add obmp-grafana/ dashboards and provisioning (17 dashboards)
- Update docker-compose.yml: add exabgp service, fix Kafka external
  listener IP, extend log retention from 90min to 720min
- Add DOCS.md: full project documentation including architecture, setup,
  user guide, sanity checks, troubleshooting, and command reference
- Update .gitignore: exclude .env and .claude/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 14:46:37 -07:00

376 lines
8.4 KiB
JSON

{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 8,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto",
"filterable": true,
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "lastmodified"
},
"properties": [
{
"id": "custom.width",
"value": 214
},
{
"id": "unit",
"value": "time: YYYY-MM-DD HH:mm:ss.SSS"
}
]
},
{
"matcher": {
"id": "byName",
"options": "localpref"
},
"properties": [
{
"id": "custom.width",
"value": 107
}
]
},
{
"matcher": {
"id": "byName",
"options": "med"
},
"properties": [
{
"id": "custom.width",
"value": 79
}
]
},
{
"matcher": {
"id": "byName",
"options": "nh"
},
"properties": [
{
"id": "custom.width",
"value": 122
}
]
},
{
"matcher": {
"id": "byName",
"options": "origin_as"
},
"properties": [
{
"id": "custom.width",
"value": 112
}
]
},
{
"matcher": {
"id": "byName",
"options": "prefix"
},
"properties": [
{
"id": "custom.width",
"value": 148
}
]
},
{
"matcher": {
"id": "byName",
"options": "routername"
},
"properties": [
{
"id": "custom.width",
"value": 216
}
]
},
{
"matcher": {
"id": "byName",
"options": "event"
},
"properties": [
{
"id": "custom.width",
"value": 112
}
]
},
{
"matcher": {
"id": "byName",
"options": "peername"
},
"properties": [
{
"id": "custom.width",
"value": 310
}
]
}
]
},
"gridPos": {
"h": 23,
"w": 23,
"x": 0,
"y": 0
},
"id": 3,
"links": [],
"options": {
"footer": {
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "9.1.7",
"targets": [
{
"alias": "",
"format": "table",
"group": [],
"hide": false,
"metricColumn": "none",
"rawQuery": true,
"rawSql": " select lastmodified,event,routername,peername,prefix,\n origin_as,nh,localpref,med,as_path,communities \n from v_ip_routes_history \n where $__timeFilter(lastmodified)\n AND peer_hash_id in ($peer_hash)\n AND communities && '{$community}'\n order by lastmodified desc,id desc\n limit $limit;",
"refId": "A",
"select": [
[
{
"params": [
"value"
],
"type": "column"
}
]
],
"timeColumn": "time",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Prefix History",
"type": "table"
}
],
"schemaVersion": 37,
"style": "dark",
"tags": [
"obmp-history"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "13445:1000",
"value": "13445:1000"
},
"hide": 0,
"includeAll": false,
"label": "Community",
"multi": false,
"name": "community",
"options": [
{
"selected": true,
"text": "13445:1000",
"value": "13445:1000"
}
],
"query": "13445:1000",
"skipUrlSync": false,
"type": "custom"
},
{
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select name as __text, hash_id as __value from routers",
"hide": 0,
"includeAll": true,
"label": "Router",
"multi": true,
"name": "router_hash",
"options": [],
"query": "select name as __text, hash_id as __value from routers",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"type": "postgres",
"uid": "obmp_postgres"
},
"definition": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash)",
"hide": 0,
"includeAll": true,
"label": "Peer",
"multi": true,
"name": "peer_hash",
"options": [],
"query": "select peername as __text, peer_hash_id as __value from v_peers where router_hash_id in ($router_hash)",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"current": {
"selected": false,
"text": "1000",
"value": "1000"
},
"hide": 0,
"includeAll": false,
"label": "Limit",
"multi": false,
"name": "limit",
"options": [
{
"selected": true,
"text": "1000",
"value": "1000"
},
{
"selected": false,
"text": "5000",
"value": "5000"
},
{
"selected": false,
"text": "10000",
"value": "10000"
}
],
"query": "1000, 5000, 10000",
"skipUrlSync": false,
"type": "custom"
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Prefix History (by Community)",
"uid": "prefix-hist-comm",
"version": 2,
"weekStart": ""
}