exercises

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

export-dashboards.sh (2791B)


      1 #!/usr/bin/env bash
      2 # Export Grafana dashboards to grafana/provisioning/dashboards/ so UI edits
      3 # can be committed to git.
      4 #
      5 # Grafana loads dashboards from those JSON files on startup, but edits made in
      6 # the UI are saved to Grafana's internal DB — not back to the files. Run this
      7 # after editing a dashboard, then `git add` the result.
      8 #
      9 # Usage:
     10 #   ./scripts/export-dashboards.sh            # export every dashboard
     11 #   ./scripts/export-dashboards.sh ad79bw7    # export one, by uid
     12 
     13 set -euo pipefail
     14 
     15 GRAFANA_URL="${GRAFANA_URL:-http://localhost:3000}"
     16 GRAFANA_AUTH="${GRAFANA_AUTH:-admin:admin}"
     17 
     18 # Resolve the output dir relative to this script, so it works from any cwd.
     19 REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
     20 OUT_DIR="$REPO_ROOT/grafana/provisioning/dashboards"
     21 mkdir -p "$OUT_DIR"
     22 
     23 # Collect the uids to export: either the one passed in, or all dashboards.
     24 if [ $# -gt 0 ]; then
     25   uids=("$@")
     26 else
     27   mapfile -t uids < <(
     28     curl -sf -u "$GRAFANA_AUTH" "$GRAFANA_URL/api/search?type=dash-db" \
     29     | python3 -c 'import sys,json; [print(d["uid"]) for d in json.load(sys.stdin)]'
     30   )
     31 fi
     32 
     33 if [ ${#uids[@]} -eq 0 ]; then
     34   echo "No dashboards found in $GRAFANA_URL" >&2
     35   exit 1
     36 fi
     37 
     38 for uid in "${uids[@]}"; do
     39   curl -sf -u "$GRAFANA_AUTH" "$GRAFANA_URL/api/dashboards/uid/$uid" \
     40   | OUT_DIR="$OUT_DIR" python3 -c '
     41 import json, os, re, sys
     42 
     43 payload = json.load(sys.stdin)
     44 dash = payload["dashboard"]
     45 
     46 # `id` is local to a Grafana instance and must not be provisioned; `uid` and
     47 # `title` are kept so this file updates the existing dashboard in place
     48 # instead of creating a duplicate.
     49 dash.pop("id", None)
     50 
     51 out_dir = os.environ["OUT_DIR"]
     52 
     53 # Reuse the file that already holds this uid, so re-exporting (or renaming a
     54 # dashboard) updates it in place. Two files sharing a uid would make Grafana
     55 # provisioning fight over which one wins.
     56 path = None
     57 for name in sorted(os.listdir(out_dir)):
     58     if not name.endswith(".json"):
     59         continue
     60     candidate = os.path.join(out_dir, name)
     61     try:
     62         with open(candidate) as fh:
     63             if json.load(fh).get("uid") == dash["uid"]:
     64                 path = candidate
     65                 break
     66     except (json.JSONDecodeError, OSError):
     67         continue
     68 
     69 # No existing file: name it from the title, lowercased, non-alphanumerics dashed.
     70 if path is None:
     71     slug = re.sub(r"[^a-z0-9]+", "-", dash["title"].lower()).strip("-") or dash["uid"]
     72     path = os.path.join(out_dir, slug + ".json")
     73 
     74 with open(path, "w") as fh:
     75     json.dump(dash, fh, indent=2)
     76     fh.write("\n")
     77 
     78 title = dash["title"]
     79 print(f"  {title}  ->  grafana/provisioning/dashboards/{os.path.basename(path)}")
     80 '
     81 done
     82 
     83 echo
     84 echo "Done. Review and commit:"
     85 echo "  git add grafana/provisioning/dashboards/ && git commit -m 'update dashboards'"