Grafana Dashboards Restore

This role restores Grafana dashboards from backup archives created by `grafana_dashboards_backup`.

Ansible Bash Grafana HTTPS JSON NAS SSL Synology

Grafana Dashboards Restore Role

Overview

This role restores Grafana dashboards from backup archives created by grafana_dashboards_backup. It automatically identifies the latest backup, extracts dashboard JSON files, and imports them into Grafana using the API with overwrite capability. The role handles conflicts gracefully by updating existing dashboards.

Purpose

  • Disaster Recovery: Restore dashboard configurations after data loss
  • Migration: Transfer dashboards to new Grafana instances
  • Environment Cloning: Replicate production dashboards in testing environments
  • Version Rollback: Restore previous dashboard versions
  • Automated Import: Batch import multiple dashboards simultaneously
  • Conflict Resolution: Overwrites existing dashboards instead of failing

Requirements

  • Ansible 2.9 or higher
  • Grafana with API access enabled
  • Grafana API token with appropriate permissions (stored in Ansible Vault)
  • Dashboard backup archives created by grafana_dashboards_backup role
  • NAS mount point accessible with backup files
  • Network connectivity to Grafana server (typically port 3000)

Role Variables

Required Variables

VariableRequiredDescription
vault_grafana_ansibleuser_api_tokenYesGrafana API token (stored in Ansible Vault)

Optional Variables

VariableDefaultDescription
grafana_dashboards_restore_backup_path/mnt/synology-ds418/grafana/dashboardsDirectory containing backup archives
grafana_dashboards_restore_host{{ hostvars['grafana']['ansible_host'] }}:3000Grafana host and port
grafana_dashboards_restore_port3000Grafana HTTP port
grafana_dashboards_restore_validate_certstrueValidate SSL certificates

Variable Details

vault_grafana_ansibleuser_api_token

Grafana API token with permissions to create/update dashboards.

Required permissions:

  • Create/update dashboards
  • Write to folders (where dashboards are created)

Example vault variable:

vault_grafana_ansibleuser_api_token: "glsa_1234567890abcdefghijklmnopqrstuvwxyz"

grafana_dashboards_restore_backup_path

Directory containing the backup tar.gz files. The role searches for files matching grafana_dashboards_*.tar.gz.

Example:

grafana_dashboards_restore_backup_path: /mnt/backup/grafana/dashboards

grafana_dashboards_restore_validate_certs

Set to false if using self-signed certificates.

Example:

grafana_dashboards_restore_validate_certs: false

Dependencies

This role has no dependencies on other Ansible roles, but requires:

  • Grafana instance accessible via HTTPS
  • Dashboard backups created by grafana_dashboards_backup role
  • NAS mount configured (if restoring from network storage)

Example Playbook

Basic Usage (Restore Latest Backup)

---
- name: Restore Grafana Dashboards
  hosts: localhost

  roles:
    - grafana_dashboards_restore

Restore to Different Grafana Instance

---
- name: Restore Dashboards to New Grafana Server
  hosts: localhost

  vars:
    grafana_dashboards_restore_host: "new-grafana.example.com:3000"
    grafana_dashboards_restore_validate_certs: true

  roles:
    - grafana_dashboards_restore

Restore with Custom Backup Location

---
- name: Restore Dashboards from Custom Backup
  hosts: localhost

  vars:
    grafana_dashboards_restore_backup_path: /mnt/backup2/grafana/dashboards

  roles:
    - grafana_dashboards_restore

What This Role Does

  1. Finds latest backup archive matching pattern grafana_dashboards_*.tar.gz
  2. Sorts by modification time and selects the most recent
  3. Fails gracefully if no backups are found
  4. Creates temporary directory for extraction
  5. Extracts backup archive to temporary location
  6. Finds all JSON files in extracted backup
  7. Reads each dashboard JSON file
  8. Imports dashboards via Grafana API with overwrite enabled
  9. Cleans up temporary files

Backup File Selection

The role automatically selects the most recent backup using these criteria:

  • Searches for files matching pattern: grafana_dashboards_*.tar.gz
  • Sorts by modification time (mtime)
  • Uses the newest file

Example backup files (newest first):

grafana_dashboards_20260107T190530.tar.gz  <- This will be used
grafana_dashboards_20260107T143022.tar.gz
grafana_dashboards_20260106T020000.tar.gz

Import Process

For each dashboard JSON file:

  1. Reads the JSON content from file
  2. Decodes base64 encoding
  3. Parses JSON structure
  4. Sets id to None (allows Grafana to assign ID)
  5. Sends POST request to /api/dashboards/db with:
    • dashboard: The dashboard JSON
    • overwrite: true (updates existing dashboards)
    • message: Restore metadata for version history

Overwrite Behavior

The role uses overwrite: true which means:

Existing dashboards with same UID: Will be updated with backup content ✅ New dashboards: Will be createdDashboard versions: New version created with restore message ✅ No conflicts: Safe to run multiple times

Version History Message:

Restored from backup grafana_dashboards_20260107T190530.tar.gz

This appears in Grafana’s dashboard version history for auditing.

Dashboard ID Handling

The role sets id: None when importing:

dashboard: "{{ (item.content | b64decode | from_json) | combine({'id': None}) }}"

Why this matters:

  • Dashboard IDs are database-specific
  • Setting id: None tells Grafana to assign appropriate ID
  • Allows same backup to be restored to multiple Grafana instances
  • Prevents ID conflicts

What Gets Restored

The restoration includes:

  • All dashboards from the backup
  • Panel configurations (visualizations, queries, thresholds)
  • Template variables
  • Annotations
  • Dashboard settings (time range, refresh, tags)
  • Panel layouts and positioning
  • Dashboard UIDs (preserved for consistency)

The restoration does NOT restore:

  • Dashboard permissions (uses defaults)
  • Folder structure (dashboards go to current user’s default folder or as specified in JSON)
  • Dashboard stars/favorites
  • Historical versions (creates new version)

Datasource Mapping

Dashboards reference datasources by UID. If datasource UIDs don’t match between source and target Grafana:

Option 1: Update datasources before restore

# Ensure target Grafana has datasources with matching UIDs
- name: Create datasources
  ansible.builtin.include_role:
    name: grafana_datasource_create

Option 2: Manual mapping in Grafana UI After import, Grafana UI prompts to map datasources if UIDs don’t match.

Option 3: Pre-process JSON files Replace old datasource UIDs with new ones before import (advanced).

API Endpoint Used

Import Dashboard

POST /api/dashboards/db
Authorization: Bearer {api_token}
Content-Type: application/json

Body:
{
  "dashboard": {dashboard_json},
  "overwrite": true,
  "message": "Restored from backup ..."
}

Response (200 OK):

{
  "id": 1,
  "uid": "abc123",
  "url": "/d/abc123/dashboard-title",
  "status": "success",
  "version": 5
}

Post-Restoration Verification

After restoration, verify in Grafana UI:

  1. Check dashboards: Browse to Dashboards
  2. Open each dashboard: Verify panels load correctly
  3. Check datasources: Ensure queries work
  4. Review variables: Test template variable dropdowns
  5. Check version history: Confirm restore message appears

Error Handling

Dashboard Import Failures

If a dashboard fails to import:

  • Role continues with remaining dashboards
  • Failed dashboard details logged in Ansible output
  • Check Grafana logs: /var/log/grafana/grafana.log

Common causes:

  • Invalid JSON format
  • Missing datasource UIDs
  • Insufficient permissions
  • Grafana version incompatibility

Security Considerations

  • API Token Protection: Token used in HTTP headers (HTTPS recommended)
  • Vault Storage: API token must be in Ansible Vault
  • Certificate Validation: Enabled by default, only disable for trusted networks
  • Overwrite Risk: Existing dashboards are overwritten without confirmation
  • Backup Before Restore: Consider backing up current dashboards before restoration

Tags

This role does not define any tags. Use playbook-level tags if needed:

- hosts: localhost
  roles:
    - grafana_dashboards_restore
  tags:
    - restore
    - grafana
    - disaster-recovery
    - dashboards

Notes

  • The role uses Grafana’s stable dashboard import API
  • Dashboards are imported individually for better error handling
  • Dashboard IDs are reset to allow Grafana to assign them
  • Temporary files are always cleaned up, even if restoration fails
  • The role is idempotent - safe to run multiple times

Troubleshooting

”No backup files found”

Verify:

  • NAS is mounted: mount | grep synology
  • Backup directory exists: ls -l /mnt/synology-ds418/grafana/dashboards/
  • Backup files exist: ls -l /mnt/synology-ds418/grafana/dashboards/grafana_dashboards_*.tar.gz

”Unauthorized” or 401 errors

Verify API token:

  • Check token is valid in Grafana UI
  • Ensure token has dashboard write permissions
  • Confirm token hasn’t expired

Test manually:

curl -X POST -H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" \
  -d '{"dashboard":{"title":"Test"},"overwrite":true}' \
  https://grafana:3000/api/dashboards/db

Dashboards imported but panels show “No Data”

Check:

  • Datasource UIDs match between source and target
  • Datasources are configured and working
  • Queries are valid for target Grafana version

Dashboard import returns “Name already exists”

This shouldn’t happen with overwrite: true. If it does:

  • Check the dashboard UID in JSON matches existing dashboard
  • Try deleting the existing dashboard manually
  • Check Grafana logs for details

SSL certificate verification fails

If using self-signed certificates:

grafana_dashboards_restore_validate_certs: false

Datasource UID warnings in Grafana UI

After import, Grafana may prompt to map datasources:

  1. Click on the datasource warning
  2. Select the correct datasource from dropdown
  3. Click “Save”

Prevent this: Ensure datasource UIDs match before import.

Performance Considerations

  • Import time depends on number of dashboards (typically 1-2 seconds per dashboard)
  • Large dashboards (many panels) take longer to import
  • API rate limiting may apply for very large restores

Typical performance:

  • 10 dashboards: ~15-20 seconds
  • 50 dashboards: ~1-2 minutes
  • 100 dashboards: ~2-3 minutes

Grafana Version Compatibility

  • Grafana 6.0+: Full support
  • Grafana 7.0+: Full support
  • Grafana 8.0+: Full support
  • Grafana 9.0+: Full support
  • Grafana 10.0+: Full support

Note: Dashboards created in newer Grafana versions may not work in older versions due to schema changes.

Migration Best Practices

When migrating dashboards between Grafana instances:

  1. Backup current state before restoration
  2. Match datasource UIDs if possible
  3. Test in staging before production
  4. Verify panel queries work in target environment
  5. Check Grafana versions are compatible
  6. Review permissions after import
  • grafana_dashboards_backup: Creates the backup files this role restores
  • grafana_alerts_restore: Restores Grafana alert rules
  • grafana_datasource_create: Configures datasources for dashboard queries
  • grafana_install: Installs and configures Grafana server

Alternative: Manual Restoration

If you need more control:

# Extract the archive
tar -xzf /mnt/synology-ds418/grafana/dashboards/grafana_dashboards_20260107T143022.tar.gz

# Import each dashboard manually via Grafana UI
# Dashboards → Import → Upload JSON file
# Or paste JSON content directly

# Or use curl
for json in *.json; do
  curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
    -H "Content-Type: application/json" \
    -d @"$json" \
    https://grafana:3000/api/dashboards/db
done

License

MIT

Author

Created for homelab infrastructure management.