A client library for accessing the Grafana HTTP API, written in Python
—
Complete dashboard lifecycle management including creation, updates, deletion, permissions, versioning, search capabilities, and dashboard folder management. This covers both individual dashboard operations and bulk management functionality.
Core dashboard management operations for creating, reading, updating, and deleting dashboards by UID or name.
def get_dashboard(self, dashboard_uid: str):
"""
Get dashboard by UID.
Args:
dashboard_uid (str): Dashboard UID
Returns:
dict: Dashboard object with metadata and JSON model
"""
...
def get_dashboard_by_name(self, dashboard_name: str):
"""
Get dashboard by name (deprecated in Grafana 8+).
Args:
dashboard_name (str): Dashboard name
Returns:
dict: Dashboard object
"""
...
def update_dashboard(self, dashboard: dict):
"""
Create or update dashboard.
Args:
dashboard (dict): Dashboard payload with dashboard object and metadata
Returns:
dict: Operation result with UID, ID, URL, and version
"""
...
def delete_dashboard(self, dashboard_uid: str):
"""
Delete dashboard by UID.
Args:
dashboard_uid (str): Dashboard UID
Returns:
dict: Deletion result
"""
...
def get_home_dashboard(self):
"""
Get the home dashboard for current user/organization.
Returns:
dict: Home dashboard object
"""
...Usage Example:
from grafana_client import GrafanaApi, TokenAuth
api = GrafanaApi(auth=TokenAuth("your-token"), host="grafana.example.com")
# Get existing dashboard
dashboard = api.dashboard.get_dashboard("dashboard-uid-here")
print(f"Dashboard: {dashboard['dashboard']['title']}")
# Create new dashboard
new_dashboard = {
"dashboard": {
"title": "My New Dashboard",
"tags": ["example", "api"],
"timezone": "browser",
"panels": [
{
"id": 1,
"title": "Sample Panel",
"type": "text",
"gridPos": {"h": 3, "w": 24, "x": 0, "y": 0},
"options": {"content": "Hello from API!"}
}
],
"time": {"from": "now-1h", "to": "now"},
"refresh": "5s"
},
"message": "Created via API",
"overwrite": False
}
result = api.dashboard.update_dashboard(new_dashboard)
print(f"Created dashboard UID: {result['uid']}")
# Update existing dashboard
dashboard['dashboard']['title'] = "Updated Title"
update_result = api.dashboard.update_dashboard({
"dashboard": dashboard['dashboard'],
"message": "Updated title",
"overwrite": True
})Operations for managing dashboard tags and retrieving tag-based information.
def get_dashboards_tags(self):
"""
Get all dashboard tags in the organization.
Returns:
list: List of tag objects with tag names and counts
"""
...Usage Example:
# Get all dashboard tags
tags = api.dashboard.get_dashboards_tags()
for tag in tags:
print(f"Tag: {tag['term']} (used by {tag['count']} dashboards)")Managing dashboard-level permissions for users, teams, and roles using both UID and ID-based methods.
def get_permissions_by_uid(self, dashboard_uid: str):
"""
Get dashboard permissions by UID.
Args:
dashboard_uid (str): Dashboard UID
Returns:
list: List of permission objects with user/team/role and permission level
"""
...
def update_permissions_by_uid(self, dashboard_uid: str, items: list):
"""
Update dashboard permissions by UID.
Args:
dashboard_uid (str): Dashboard UID
items (list): List of permission objects
"""
...
def get_permissions_by_id(self, dashboard_id: int):
"""
Get dashboard permissions by ID (deprecated, use UID method).
Args:
dashboard_id (int): Dashboard ID
Returns:
list: List of permission objects
"""
...
def update_permissions_by_id(self, dashboard_id: int, items: list):
"""
Update dashboard permissions by ID (deprecated, use UID method).
Args:
dashboard_id (int): Dashboard ID
items (list): List of permission objects
"""
...
def get_dashboard_permissions(self, dashboard_id: int):
"""
Get dashboard permissions by ID (deprecated, use get_permissions_by_id).
Args:
dashboard_id (int): Dashboard ID
Returns:
list: List of permission objects
"""
...
def update_dashboard_permissions(self, dashboard_id: int, items: list):
"""
Update dashboard permissions by ID (deprecated, use update_permissions_by_id).
Args:
dashboard_id (int): Dashboard ID
items (list): List of permission objects
"""
...
def get_permissions_generic(self, identifier: str, idtype: str = "uid"):
"""
Generic method to get permissions by identifier.
Args:
identifier (str): Dashboard identifier (UID or ID)
idtype (str): Identifier type ("uid" or "id")
Returns:
list: List of permission objects
"""
...
def update_permissions_generic(self, identifier: str, items: list, idtype: str = "uid"):
"""
Generic method to update permissions by identifier.
Args:
identifier (str): Dashboard identifier (UID or ID)
items (list): List of permission objects
idtype (str): Identifier type ("uid" or "id")
"""
...Permission Object Structure:
# Permission item structure
permission_item = {
"userId": 0, # User ID (optional, mutually exclusive with teamId/role)
"teamId": 0, # Team ID (optional, mutually exclusive with userId/role)
"role": "Viewer", # Built-in role (optional, mutually exclusive with userId/teamId)
"permission": 1 # Permission level: 1=View, 2=Edit, 4=Admin
}Usage Example:
# Get current permissions
permissions = api.dashboard.get_permissions_by_uid("dashboard-uid")
for perm in permissions:
if 'userId' in perm:
print(f"User {perm['userId']}: {perm['permissionName']}")
elif 'teamId' in perm:
print(f"Team {perm['teamId']}: {perm['permissionName']}")
elif 'role' in perm:
print(f"Role {perm['role']}: {perm['permissionName']}")
# Update permissions
new_permissions = [
{
"teamId": 2,
"permission": 2 # Edit permission
},
{
"role": "Editor",
"permission": 1 # View permission
},
{
"userId": 5,
"permission": 4 # Admin permission
}
]
api.dashboard.update_permissions_by_uid("dashboard-uid", new_permissions)
print("Permissions updated successfully")Dashboard search is handled through the Search API element but often used in dashboard workflows.
# Search for dashboards by various criteria
search_results = api.search.search_dashboards(
query="production", # Text query
tags=["monitoring"], # Filter by tags
folderIds=[1, 2], # Filter by folder IDs
type="dash-db", # Type filter
starred=True, # Only starred dashboards
limit=50 # Result limit
)
for dashboard in search_results:
print(f"Found: {dashboard['title']} (UID: {dashboard['uid']})")Dashboard folder operations are managed through the Folder API but commonly used with dashboard management.
# Create folder for dashboards
folder_result = api.folder.create_folder(
title="Production Dashboards",
uid="prod-dashboards"
)
# Create dashboard in specific folder
dashboard_with_folder = {
"dashboard": {
"title": "Production Metrics",
"tags": ["production"],
"panels": []
},
"folderId": folder_result['id'], # Assign to folder
"message": "Created in production folder"
}
result = api.dashboard.update_dashboard(dashboard_with_folder)Dashboard Starring:
# Star/unstar dashboards (through User API)
api.user.star_actual_user_dashboard(dashboard_id=123)
api.user.unstar_actual_user_dashboard(dashboard_id=123)Dashboard Snapshots:
# Create dashboard snapshot (through Snapshots API)
snapshot_data = {
"dashboard": dashboard['dashboard'],
"name": "Production Snapshot",
"expires": 3600, # Expires in 1 hour
"external": False
}
snapshot_result = api.snapshots.create_new_snapshot(**snapshot_data)
print(f"Snapshot URL: {snapshot_result['url']}")Common dashboard operation errors and how to handle them:
from grafana_client import GrafanaClientError, GrafanaBadInputError
try:
# Attempt to get dashboard
dashboard = api.dashboard.get_dashboard("non-existent-uid")
except GrafanaClientError as e:
if e.status_code == 404:
print("Dashboard not found")
elif e.status_code == 403:
print("Access denied - insufficient permissions")
else:
print(f"Client error: {e.message}")
try:
# Attempt to create dashboard with invalid data
invalid_dashboard = {
"dashboard": {
# Missing required fields
}
}
api.dashboard.update_dashboard(invalid_dashboard)
except GrafanaBadInputError as e:
print(f"Invalid dashboard data: {e.message}")All dashboard operations support async versions:
import asyncio
from grafana_client import AsyncGrafanaApi, TokenAuth
async def manage_dashboards():
api = AsyncGrafanaApi(auth=TokenAuth("your-token"), host="grafana.example.com")
# Async dashboard operations
dashboard = await api.dashboard.get_dashboard("dashboard-uid")
tags = await api.dashboard.get_dashboards_tags()
permissions = await api.dashboard.get_permissions_by_uid("dashboard-uid")
# Concurrent operations
dashboard_tasks = [
api.dashboard.get_dashboard(uid)
for uid in ["uid1", "uid2", "uid3"]
]
dashboards = await asyncio.gather(*dashboard_tasks)
print(f"Retrieved {len(dashboards)} dashboards")
asyncio.run(manage_dashboards())Understanding the dashboard JSON structure for creation and updates:
# Complete dashboard structure example
dashboard_json = {
"dashboard": {
"id": None, # Auto-generated, set to null for new dashboards
"uid": "custom-uid", # Optional custom UID
"title": "My Dashboard",
"description": "Dashboard created via API",
"tags": ["api", "example"],
"timezone": "browser", # "browser", "utc", or timezone string
"editable": True,
"hideControls": False,
"schemaVersion": 30, # Grafana schema version
"version": 0, # Auto-incremented
"refresh": "5s", # Auto-refresh interval
"time": { # Time range
"from": "now-6h",
"to": "now"
},
"timepicker": { # Time picker configuration
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
},
"templating": { # Variables/templating
"list": []
},
"annotations": { # Annotations configuration
"list": []
},
"panels": [ # Dashboard panels
{
"id": 1,
"title": "Sample Panel",
"type": "stat",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
"fieldConfig": {
"defaults": {},
"overrides": []
},
"options": {},
"targets": [ # Data queries
{
"expr": "up",
"refId": "A"
}
]
}
]
},
"message": "Created via API", # Commit message
"overwrite": False, # Overwrite existing dashboard
"folderId": 0 # Folder ID (0 = General folder)
}Install with Tessl CLI
npx tessl i tessl/pypi-grafana-client@5.0.1