Complete Grafana Automation with Ansible: CRUD Operations Guide
Master Grafana automation with Ansible playbooks. Complete guide covering datasources, dashboards, users, alerts, and multi-environment deployments with CRUD operations, security best practices, and production-ready examples.
Automate Grafana management with comprehensive Ansible playbooks for datasources, dashboards, users, and alerts. This complete Grafana automation guide covers CRUD operations, multi-environment deployments, and production-ready Infrastructure as Code practices.
Quick Start: Jump to ready-to-use examples for immediate automation or explore our GitHub repository for complete automation suite including Ansible, guides, and documentation.
Complete guide for managing Grafana resources using Ansible.
Table of Contents
- Architecture Overview
- When to Use Ansible for Grafana
- Prerequisites
- Quick Start (5 Minutes)
- Collection Information
- Compatibility
- Configuration & Execution
- Module Compatibility & Status
- Ready-to-Use Examples
- Core Modules
- Alerting Management
- User Management
- Cloud Services Management
- Best Practices
- Frequently Asked Questions (FAQ)
- Troubleshooting
- References
Architecture Overview
The following diagram shows how Ansible interacts with different Grafana deployments:
graph TB
A[Ansible Control Node] --> B[Inventory & Variables]
A --> C[Playbooks]
C --> D[grafana.grafana Collection]
D --> E[API Calls]
E --> F[Self-hosted Grafana]
E --> G[Grafana Cloud]
E --> H[Azure Managed Grafana]
E --> I[Amazon Managed Grafana]
B --> J[host_vars/]
B --> K[group_vars/]
B --> L[Encrypted Vault Files]
F --> M[Common Resources]
G --> M
H --> M
I --> M
M --> N[Datasources]
M --> O[Dashboards]
M --> P[Users]
M --> Q[Alerts]
style A fill:#e1f5fe
style D fill:#f3e5f5
style F fill:#e8f5e8
style G fill:#fff3e0
style H fill:#e3f2fd
style I fill:#fce4ec
style M fill:#f0f4c3
When to Use Ansible for Grafana
Ideal Use Cases:
- Multi-environment deployments - Consistent setup across dev/staging/prod
- Infrastructure as Code - Version-controlled Grafana configurations
- Bulk operations - Managing multiple datasources, dashboards, users
- Standardization - Enforcing organizational standards and policies
- Disaster recovery - Automated recreation of Grafana setups
- CI/CD integration - Automated deployment pipelines
- Team onboarding - Consistent user and permission setup
- Compliance - Auditable configuration management
Not Recommended For:
- One-time manual tasks - Use Grafana UI instead
- Frequent dashboard edits - Use Grafana editor for iterative development
- Real-time troubleshooting - Direct API calls are faster
- Small single-instance setups - Manual configuration may be simpler
Prerequisites
1
2
3
4
5
6
7
8
9
10
11
# Install Ansible (2.12.0 or newer)
pip3 install ansible
# Install required Python libraries
pip3 install requests
# Install Grafana collection
ansible-galaxy collection install grafana.grafana
# Verify installation
ansible-galaxy collection list | grep grafana
Quick Start (5 Minutes)
Get your first Grafana automation running in 5 minutes:
1. Clone and setup:
1
2
git clone https://github.com/sagarnikam123/sagarnikam123-blog-youtube-code-samples.git
cd sagarnikam123-blog-youtube-code-samples/grafana-automation/
2. Configure your Grafana URL and API key:
1
2
3
# Quick setup for local Grafana
echo "grafana_url: http://localhost:3000" > host_vars/grafana-local.yml
echo "grafana_api_key: your-api-key-here" >> host_vars/grafana-local.yml
3. Test and create your first resource:
1
2
3
4
5
# Test connection
ansible-playbook -i inventory.ini grafana_info.yml --limit grafana-local
# Create a folder
ansible-playbook -i inventory.ini operations/folder/folder_create.yml --limit grafana-local
✅ Success! Continue to Configuration & Execution for production setups and advanced examples.
Collection Information
Collection: grafana.grafana
v6.0.4+ Supported ansible-core: 2.12.0 or newer (< 3.0.0) Authors: Grafana Labs, Ishan Jain, Gerard van Engelen Documentation: https://docs.ansible.com/ansible/latest/collections/grafana/grafana/ Tested With: Ansible 2.17.13, Python 3.13.5, grafana.grafana 6.0.5
Compatibility
This guide’s examples work with:
- Self-hosted Grafana - On-premises or VM installations
- Grafana Cloud - SaaS offering by Grafana Labs
- Azure Managed Grafana - Azure’s managed service
- Amazon Managed Grafana - AWS’s managed service
For managed services, simply update the grafana_url
to point to your managed instance endpoint and use the appropriate API keys.
Configuration & Execution
Method 1: Direct Variables (Testing)
Config: Pass variables directly using -e
Use Case: Development and testing
Execution:
1
2
# Test connection and get info
ansible-playbook grafana_info.yml -e "grafana_url=http://localhost:3000" -e "grafana_api_key=token"
Method 2: Development Setup (Recommended)
Config: Variables stored in host_vars/group_vars files Use Case: Development and testing (this guide focuses on this approach)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# inventory.ini - for API-based Grafana management
[grafana_prod]
grafana-prod-1 ansible_host=your-prod-grafana-1.example.com ansible_connection=local
grafana-prod-2 ansible_host=your-prod-grafana-2.example.com ansible_connection=local
[grafana_staging]
grafana-staging-1 ansible_host=your-staging-grafana.example.com ansible_connection=local
[grafana_dev]
grafana-dev-1 ansible_host=your-dev-grafana.example.com ansible_connection=local
[grafana_cloud]
grafana-cloud-1 ansible_host=your-org.grafana.net ansible_connection=local
[grafana_local]
grafana-local ansible_host=localhost ansible_connection=local
[all_grafana:children]
grafana_prod
grafana_staging
grafana_dev
grafana_cloud
grafana_local
Important: ansible_connection=local
prevents SSH attempts and runs tasks locally. This is required for Grafana API management since:
- Grafana instances are API endpoints, not SSH servers
- Amazon Managed Grafana/Grafana Cloud don’t allow SSH access
- All API calls are made from your local machine to Grafana URLs
- Variables like
grafana_url
andgrafana_api_key
are stored inhost_vars/
orgroup_vars/
files
Execution: See Common Execution Options below for detailed examples.
💡 Tip: If you completed the Quick Start, you’re already using Method 2. The examples below show additional configuration options and multi-environment setups.
Method 3: Production Setup
Config: Same structure as Method 2 but with encrypted credentials Use Case: Production environments
1
2
3
4
5
6
7
8
9
10
11
12
# group_vars/grafana_prod.yml - shared production settings
grafana_environment: "production"
grafana_admin_name: "<admin_username>" # Only needed for user management
grafana_admin_password: "<admin_password>" # Only needed for user management
# host_vars/grafana-prod-1.yml - encrypted in production
grafana_url: "https://<your-prod-grafana-1>.example.com"
grafana_api_key: "<your-prod-1-api-token>"
# host_vars/grafana-prod-2.yml - encrypted in production
grafana_url: "https://<your-prod-grafana-2>.example.com"
grafana_api_key: "<your-prod-2-api-token>"
For production: Encrypt sensitive files using ansible-vault encrypt host_vars/grafana-prod-*.yml
Note: grafana_admin_name
and grafana_admin_password
are only required for user management operations. Most automation (datasources, dashboards, folders) uses API keys only.
Execution: See Common Execution Options below for detailed examples.
🔒 Security: This method encrypts sensitive data using
ansible-vault
. For development/testing, you can use Method 2 without encryption.
Common Execution Options (for both Method 2 & Method 3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Note: --check mode not useful for info playbooks (they only read data)
# Use --check mode for playbooks that make changes (create/update/delete)
ansible-playbook -i inventory.ini operations/folder/folder_crud_workflow.yml --check -e target_hosts=grafana_local
# Verbose output levels
ansible-playbook -i inventory.ini grafana_info.yml -v -e target_hosts=grafana_local # Basic verbose
ansible-playbook -i inventory.ini grafana_info.yml -vv -e target_hosts=grafana_local # More verbose
ansible-playbook -i inventory.ini grafana_info.yml -vvv -e target_hosts=grafana_local # Debug level
# Combine with additional variables
ansible-playbook -i inventory.ini grafana_info.yml -e "grafana_timeout=30" -e target_hosts=grafana_local
ansible-playbook -i inventory.ini grafana_info.yml -e "environment=production" -e target_hosts=grafana_prod
# Run against specific hosts/groups
ansible-playbook -i inventory.ini grafana_info.yml --limit grafana_prod -e target_hosts=grafana_prod
ansible-playbook -i inventory.ini grafana_info.yml --limit "grafana-prod-1,grafana-staging-1" -e target_hosts="grafana-prod-1,grafana-staging-1"
# Target single host from group
ansible-playbook -i inventory.ini grafana_info.yml --limit grafana_prod -e target_hosts=grafana-prod-1
# Target multiple specific hosts
ansible-playbook -i inventory.ini grafana_info.yml -e target_hosts="grafana-prod-1,grafana-prod-2"
# Target entire group
ansible-playbook -i inventory.ini grafana_info.yml -e target_hosts=all_grafana
# Target hosts from different groups
ansible-playbook -i inventory.ini grafana_info.yml -e target_hosts="grafana-prod-1,grafana-local"
# For production with encrypted host_vars
ansible-playbook -i inventory.ini grafana_info.yml --ask-vault-pass -e target_hosts=grafana_prod
Module Compatibility & Status
Module | Purpose | Usage | Status |
---|---|---|---|
datasource | Data sources | ⭐⭐⭐ Essential | ✅ Working |
folder | Folders | ⭐⭐⭐ Essential | ✅ Working |
dashboard | Dashboards | ⭐⭐⭐ Essential | ✅ Working |
user | Users | ⭐⭐ Common | ✅ Working |
alert_contact_point | Alert contacts | ⭐⭐ Common | ✅ Working |
alert_notification_policy | Alert policies | ⭐⭐ Common | ✅ Working |
cloud_stack | Cloud stacks | ⭐ Cloud Only | 🔶 Limited |
cloud_api_key | Cloud API keys | ⭐ Cloud Only | ❌ Broken |
cloud_plugin | Cloud plugins | ⭐ Cloud Only | ❌ Broken (#453) |
Important Note: The grafana.grafana
collection modules are primarily designed for managing (Create/Update/Delete) resources, not for retrieving information. However, this guide provides complete CRUD operations by adding READ functionality using Ansible’s uri
module to interact directly with Grafana’s REST API. This combination gives you full control over all Grafana resources with proper Create, Read, Update, and Delete capabilities.
Status Legend:
- ✅ Working: Module functions correctly for all operations
- 🔶 Limited: Module works but has restrictions (tier limits, permissions, etc.)
- ❌ Broken: Module has issues preventing normal operation
Ready-to-Use Examples
The grafana-automation/ansible/
folder contains ready-to-use playbooks and configuration files:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
grafana-automation/ansible/
├── inventory.ini # Inventory for all environments
├── grafana_info.yml # Get comprehensive Grafana info
├── README.md # Setup and usage documentation
├── host_vars/ # Host-specific variables
│ ├── grafana-local.yml # Local development
│ ├── grafana-prod-1.yml # Production instance 1
│ ├── grafana-prod-2.yml # Production instance 2
│ ├── grafana-dev-1.yml # Development instance
│ ├── grafana-staging-1.yml # Staging instance
│ └── grafana-cloud.yml # Grafana Cloud instance
├── group_vars/ # Environment-specific shared settings
│ ├── grafana_prod.yml # Production settings
│ ├── grafana_staging.yml # Staging settings
│ ├── grafana_dev.yml # Development settings
│ ├── grafana_cloud.yml # Cloud settings
│ └── grafana_local.yml # Local settings
└── operations/ # Management operations
├── folder/ # Folder operations
│ ├── folder_create.yml
│ ├── folder_read.yml
│ ├── folder_update.yml
│ ├── folder_delete.yml
│ └── folder_crud_workflow.yml
├── datasource/ # Datasource operations
│ ├── datasource_create.yml
│ ├── datasource_read.yml
│ ├── datasource_update.yml
│ ├── datasource_delete.yml
│ └── datasource_crud_workflow.yml
├── dashboard/ # Dashboard operations
│ ├── dashboard_create.yml
│ ├── dashboard_read.yml
│ ├── dashboard_update.yml
│ ├── dashboard_delete.yml
│ └── dashboard_crud_workflow.yml
├── user/ # User operations
│ ├── user_create.yml
│ ├── user_read.yml
│ ├── user_update.yml
│ ├── user_delete.yml
│ └── user_crud_workflow.yml
├── alert_contact_point/ # Alert contact point operations
│ ├── alert_contact_point_create.yml
│ ├── alert_contact_point_read.yml
│ ├── alert_contact_point_update.yml
│ ├── alert_contact_point_delete.yml
│ └── alert_contact_point_crud_workflow.yml
├── alert_notification_policy/ # Alert notification policy operations
│ ├── alert_notification_policy_create.yml
│ ├── alert_notification_policy_read.yml
│ ├── alert_notification_policy_update.yml
│ ├── alert_notification_policy_delete.yml
│ └── alert_notification_policy_crud_workflow.yml
├── cloud_api_key/ # Cloud API key operations
│ ├── cloud_api_key_create.yml
│ ├── cloud_api_key_read.yml
│ ├── cloud_api_key_update.yml
│ ├── cloud_api_key_delete.yml
│ └── cloud_api_key_crud_workflow.yml
├── cloud_plugin/ # Cloud plugin operations
│ ├── cloud_plugin_create.yml
│ ├── cloud_plugin_read.yml
│ ├── cloud_plugin_update.yml
│ ├── cloud_plugin_delete.yml
│ └── cloud_plugin_crud_workflow.yml
└── cloud_stack/ # Cloud stack operations
├── cloud_stack_create.yml
├── cloud_stack_read.yml
├── cloud_stack_update.yml
├── cloud_stack_delete.yml
└── cloud_stack_crud_workflow.yml
Core Modules
Folder Management
Files: grafana-automation/ansible/operations/folder/
- Individual CRUD operations or folder_crud_workflow.yml
for complete workflow
Create Operations (operations/folder/folder_create.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- name: Create single folder
grafana.grafana.folder:
grafana_url: ""
grafana_api_key: ""
title: "System Monitoring"
uid: "system-monitoring"
overwrite: true
state: present
- name: Create multiple folders
grafana.grafana.folder:
grafana_url: ""
grafana_api_key: ""
title: ""
uid: ""
overwrite: true
state: present
loop:
- { title: "Infrastructure", uid: "infrastructure" }
- { title: "Applications", uid: "applications" }
- { title: "Security", uid: "security" }
Read Operations (operations/folder/folder_read.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- name: Get all folders
uri:
url: "/api/folders"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
register: folders_result
- name: Display all folders
debug:
var: folders_result.json
- name: Get specific folder by UID
uri:
url: "/api/folders/"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
status_code: [200, 404]
vars:
folder_uid: "system-monitoring"
register: folder_info
- name: Display specific folder
debug:
var: folder_info.json
when: folder_info.status == 200
Update Operations (operations/folder/folder_update.yml
):
1
2
3
4
5
6
7
8
- name: Update folder title
grafana.grafana.folder:
grafana_url: ""
grafana_api_key: ""
title: "Infrastructure Monitoring" # Updated title
uid: "infrastructure"
overwrite: true
state: present
Delete Operations (operations/folder/folder_delete.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- name: Delete single folder
grafana.grafana.folder:
grafana_url: ""
grafana_api_key: ""
title: "Security" # Required even for deletion
uid: "security"
state: absent
ignore_errors: true
- name: Delete multiple folders
grafana.grafana.folder:
grafana_url: ""
grafana_api_key: ""
title: ""
uid: ""
state: absent
loop:
- { title: "Infrastructure", uid: "infrastructure" }
- { title: "Applications", uid: "applications" }
ignore_errors: true
How to Run:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Create folders
ansible-playbook -i inventory.ini operations/folder/folder_create.yml -e target_hosts=grafana_local
# Read folders
ansible-playbook -i inventory.ini operations/folder/folder_read.yml -e target_hosts=grafana_local
# Update folders
ansible-playbook -i inventory.ini operations/folder/folder_update.yml -e target_hosts=grafana_local
# Delete folders
ansible-playbook -i inventory.ini operations/folder/folder_delete.yml -e target_hosts=grafana_local
# Complete CRUD workflow
ansible-playbook -i inventory.ini operations/folder/folder_crud_workflow.yml -e target_hosts=grafana_local
Datasource Management
Files: grafana-automation/ansible/operations/datasource/
- Individual CRUD operations or datasource_crud_workflow.yml
for complete workflow
Create Operations (operations/datasource/datasource_create.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
- name: Create Prometheus datasource
grafana.grafana.datasource:
dataSource: |
{
"name": "Prometheus",
"type": "prometheus",
"access": "proxy",
"url": "http://localhost:9090",
"isDefault": true,
"jsonData": {
"httpMethod": "POST",
"manageAlerts": true,
"prometheusType": "Prometheus",
"cacheLevel": "High"
}
}
grafana_url: ""
grafana_api_key: ""
state: present
- name: Create multiple datasources
grafana.grafana.datasource:
dataSource: ""
grafana_url: ""
grafana_api_key: ""
state: present
loop:
- name: "Loki"
type: "loki"
access: "proxy"
url: "http://localhost:3100"
jsonData:
maxLines: 1000
- name: "InfluxDB"
type: "influxdb"
access: "proxy"
url: "http://localhost:8086"
database: "telegraf"
user: "admin"
jsonData:
httpMode: "GET"
- name: "MySQL"
type: "mysql"
access: "proxy"
url: "localhost:3306"
database: "grafana"
user: "grafana_user"
secureJsonData:
password: "<grafana_password>"
Read Operations (operations/datasource/datasource_read.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- name: Get all datasources
uri:
url: "/api/datasources"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
register: datasources_result
- name: Display all datasources
debug:
var: datasources_result.json
- name: Get specific datasource by name
uri:
url: "/api/datasources/name/"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
status_code: [200, 404]
vars:
datasource_name: "Prometheus"
register: datasource_info
- name: Display specific datasource
debug:
var: datasource_info.json
when: datasource_info.status == 200
Update Operations (operations/datasource/datasource_update.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- name: Update Prometheus datasource configuration
grafana.grafana.datasource:
dataSource: |
{
"name": "Prometheus",
"type": "prometheus",
"access": "proxy",
"url": "http://prometheus-server:9090",
"isDefault": true,
"jsonData": {
"httpMethod": "GET",
"manageAlerts": false,
"prometheusType": "Prometheus",
"cacheLevel": "Low",
"timeInterval": "30s"
}
}
grafana_url: ""
grafana_api_key: ""
state: present
Delete Operations (operations/datasource/datasource_delete.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- name: Delete datasource by name
grafana.grafana.datasource:
dataSource:
name: "InfluxDB"
grafana_url: ""
grafana_api_key: ""
state: absent
ignore_errors: true
- name: Delete multiple datasources
grafana.grafana.datasource:
dataSource:
name: ""
grafana_url: ""
grafana_api_key: ""
state: absent
loop:
- "Loki"
- "Prometheus"
ignore_errors: true
How to Run:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Create datasources
ansible-playbook -i inventory.ini operations/datasource/datasource_create.yml -e target_hosts=grafana_local
# Read datasources
ansible-playbook -i inventory.ini operations/datasource/datasource_read.yml -e target_hosts=grafana_local
# Update datasources
ansible-playbook -i inventory.ini operations/datasource/datasource_update.yml -e target_hosts=grafana_local
# Delete datasources
ansible-playbook -i inventory.ini operations/datasource/datasource_delete.yml -e target_hosts=grafana_local
# Complete CRUD workflow
ansible-playbook -i inventory.ini operations/datasource/datasource_crud_workflow.yml -e target_hosts=grafana_local
Finding jsonData Parameters
Method 1: Grafana UI (Recommended)
- Go to Configuration → Data Sources
- Add datasource manually via UI
- Configure all settings → Save & Test
- Use browser dev tools → Network tab
- Look for POST request to
/api/datasources
- Copy
jsonData
from request payload
Method 2: Export Existing Datasource
1
2
3
# Get by name
curl -X GET "$GRAFANA_URL/api/datasources/name/Prometheus" \
-H "Authorization: Bearer $GRAFANA_TOKEN" | jq '.jsonData'
Common Parameters:
- Prometheus:
{"httpMethod": "POST", "manageAlerts": true, "prometheusType": "Prometheus", "cacheLevel": "High"}
- Loki:
{"maxLines": 1000, "derivedFields": []}
- InfluxDB:
{"httpMode": "GET", "keepCookies": []}
Dashboard Management
Files: grafana-automation/ansible/operations/dashboard/
- Individual CRUD operations or dashboard_crud_workflow.yml
for complete workflow
Create Operations (operations/dashboard/dashboard_create.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
- name: Download Node Exporter dashboard JSON
uri:
url: "https://grafana.com/api/dashboards/1860/revisions/37/download"
method: GET
return_content: yes
register: node_exporter_dashboard
- name: Debug downloaded dashboard structure
debug:
msg: "Dashboard keys: {{ node_exporter_dashboard.json.keys() | list }}"
- name: Import Node Exporter dashboard
grafana.grafana.dashboard:
grafana_url: ""
grafana_api_key: ""
dashboard:
dashboard: ""
overwrite: true
state: present
- name: Download and import multiple dashboards
uri:
url: "https://grafana.com/api/dashboards//revisions//download"
method: GET
return_content: yes
register: dashboard_json
loop:
- { id: 13639, revision: 2, name: "Loki Dashboard" } # by Sadlil
- { id: 12019, revision: 1, name: "Grafana Stats" } # by eldintest
loop_control:
loop_var: item
label: ""
- name: Import downloaded dashboards
grafana.grafana.dashboard:
grafana_url: ""
grafana_api_key: ""
dashboard:
dashboard: ""
overwrite: true
state: present
loop: ""
loop_control:
label: "Dashboard import"
- name: Create simple custom dashboard
grafana.grafana.dashboard:
grafana_url: ""
grafana_api_key: ""
dashboard:
dashboard:
title: "Simple Dashboard"
uid: "simple-dashboard"
tags: ["ansible"]
timezone: "browser"
panels: []
time:
from: "now-6h"
to: "now"
refresh: "5s"
overwrite: true
state: present
Read Operations (operations/dashboard/dashboard_read.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
- name: Search all dashboards
uri:
url: "/api/search?type=dash-db"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
register: dashboards_search
- name: Display dashboards
debug:
var: dashboards_search.json
Update Operations (operations/dashboard/dashboard_update.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- name: Update simple dashboard title
grafana.grafana.dashboard:
grafana_url: ""
grafana_api_key: ""
dashboard:
dashboard:
title: "Simple Dashboard - Updated"
uid: "simple-dashboard"
tags: ["ansible", "updated"]
timezone: "browser"
panels: []
time:
from: "now-12h"
to: "now"
refresh: "10s"
overwrite: true
state: present
Delete Operations (operations/dashboard/dashboard_delete.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- name: Get all dashboards to see what exists
uri:
url: "/api/search?type=dash-db"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
register: existing_dashboards
- name: Display existing dashboards
debug:
msg: "Found dashboards: {{ existing_dashboards.json | map(attribute='uid') | list }}"
- name: Delete dashboards by UID
grafana.grafana.dashboard:
grafana_url: ""
grafana_api_key: ""
dashboard:
dashboard:
uid: ""
state: absent
loop:
- "cpu-monitoring" # CPU Monitoring dashboard
- "rYdddlPWk" # Node Exporter dashboard
- "system-overview" # System Overview dashboard
ignore_errors: yes
loop_control:
label: "Deleting dashboard "
How to Run:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Create dashboards
ansible-playbook -i inventory.ini operations/dashboard/dashboard_create.yml -e target_hosts=grafana_local
# Read dashboards
ansible-playbook -i inventory.ini operations/dashboard/dashboard_read.yml -e target_hosts=grafana_local
# Update dashboards
ansible-playbook -i inventory.ini operations/dashboard/dashboard_update.yml -e target_hosts=grafana_local
# Delete dashboards
ansible-playbook -i inventory.ini operations/dashboard/dashboard_delete.yml -e target_hosts=grafana_local
# Complete CRUD workflow
ansible-playbook -i inventory.ini operations/dashboard/dashboard_crud_workflow.yml -e target_hosts=grafana_local
Alerting Management
Alert Contact Point Management
Files: grafana-automation/ansible/operations/alert_contact_point/
- Individual CRUD operations for contact points
Create Operations (operations/alert_contact_point/alert_contact_point_create.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- name: Create email contact point
grafana.grafana.alert_contact_point:
grafana_url: ""
grafana_api_key: ""
name: "ops-email"
uid: "opsemail"
type: "email"
settings:
addresses: "admin@example.com,team@example.com"
subject: "Grafana Alert"
disableResolveMessage: false
state: present
- name: Create slack contact point
grafana.grafana.alert_contact_point:
grafana_url: ""
grafana_api_key: ""
name: "ops-slack"
uid: "opsslack"
type: "slack"
settings:
url: "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
channel: "#alerts"
username: "Grafana"
disableResolveMessage: false
state: present
Read Operations (operations/alert_contact_point/alert_contact_point_read.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
- name: Get all contact points
uri:
url: "/api/v1/provisioning/contact-points"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
register: contact_points_result
- name: Display contact points
debug:
var: contact_points_result.json
Update Operations (operations/alert_contact_point/alert_contact_point_update.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
- name: Update email contact point settings
grafana.grafana.alert_contact_point:
grafana_url: ""
grafana_api_key: ""
name: "ops-email"
uid: "opsemail-updated"
type: "email"
settings:
addresses: "admin@example.com,team@example.com,oncall@example.com"
subject: "Grafana Alert - Updated"
disableResolveMessage: false
state: present
Delete Operations (operations/alert_contact_point/alert_contact_point_delete.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- name: Delete email contact point
grafana.grafana.alert_contact_point:
grafana_url: ""
grafana_api_key: ""
name: "ops-email"
uid: "opsemail"
type: "email"
settings:
addresses: "admin@example.com,team@example.com"
subject: "Grafana Alert"
state: absent
ignore_errors: true
- name: Delete slack contact point
grafana.grafana.alert_contact_point:
grafana_url: ""
grafana_api_key: ""
name: "ops-slack"
uid: "opsslack"
type: "slack"
settings:
url: "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
channel: "#alerts"
username: "Grafana"
state: absent
ignore_errors: true
How to Run:
1
2
3
4
5
6
7
8
9
10
11
# Create contact points
ansible-playbook -i inventory.ini operations/alert_contact_point/alert_contact_point_create.yml -e target_hosts=grafana_local
# Read contact points
ansible-playbook -i inventory.ini operations/alert_contact_point/alert_contact_point_read.yml -e target_hosts=grafana_local
# Update contact points
ansible-playbook -i inventory.ini operations/alert_contact_point/alert_contact_point_update.yml -e target_hosts=grafana_local
# Delete contact points
ansible-playbook -i inventory.ini operations/alert_contact_point/alert_contact_point_delete.yml -e target_hosts=grafana_local
Alert Notification Policy Management
Files: grafana-automation/ansible/operations/alert_notification_policy/
- Individual CRUD operations for notification policies
Create Operations (operations/alert_notification_policy/alert_notification_policy_create.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- name: Create basic notification policy
grafana.grafana.alert_notification_policy:
grafana_url: ""
grafana_api_key: ""
rootPolicyReceiver: "grafana-default-email"
groupByStr: ["alertname", "cluster"]
groupWait: "10s"
groupInterval: "5m"
repeatInterval: "12h"
routes:
- receiver: "grafana-default-email"
object_matchers: [["severity", "=", "critical"]]
- receiver: "grafana-default-email"
object_matchers: [["env", "=", "production"]]
Read Operations (operations/alert_notification_policy/alert_notification_policy_read.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
- name: Get notification policies
uri:
url: "/api/v1/provisioning/policies"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
register: policies_result
- name: Display notification policies
debug:
var: policies_result.json
Update Operations (operations/alert_notification_policy/alert_notification_policy_update.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- name: Update notification policy settings
grafana.grafana.alert_notification_policy:
grafana_url: ""
grafana_api_key: ""
rootPolicyReceiver: "grafana-default-email"
groupByStr: ["alertname", "cluster", "severity"]
groupWait: "15s"
groupInterval: "10m"
repeatInterval: "24h"
routes:
- receiver: "grafana-default-email"
object_matchers: [["severity", "=", "critical"]]
- receiver: "grafana-default-email"
object_matchers: [["severity", "=", "warning"]]
- receiver: "grafana-default-email"
object_matchers: [["team", "=", "infrastructure"]]
Delete Operations (operations/alert_notification_policy/alert_notification_policy_delete.yml
):
1
2
3
4
5
6
7
8
9
10
11
- name: Reset notification policy to default
grafana.grafana.alert_notification_policy:
grafana_url: ""
grafana_api_key: ""
rootPolicyReceiver: "grafana-default-email"
groupByStr: []
groupWait: "30s"
groupInterval: "5m"
repeatInterval: "4h"
routes: []
ignore_errors: true
Note: Notification policies don’t have a traditional “delete” operation. Instead, this resets the policy to default configuration since Grafana requires a root notification policy to always exist.
How to Run:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Create notification policies
ansible-playbook -i inventory.ini operations/alert_notification_policy/alert_notification_policy_create.yml -e target_hosts=grafana_local
# Read notification policies
ansible-playbook -i inventory.ini operations/alert_notification_policy/alert_notification_policy_read.yml -e target_hosts=grafana_local
# Update notification policies
ansible-playbook -i inventory.ini operations/alert_notification_policy/alert_notification_policy_update.yml -e target_hosts=grafana_local
# Reset notification policies to default
ansible-playbook -i inventory.ini operations/alert_notification_policy/alert_notification_policy_delete.yml -e target_hosts=grafana_local
# Complete CRUD workflow
ansible-playbook -i inventory.ini operations/alert_notification_policy/alert_notification_policy_crud_workflow.yml -e target_hosts=grafana_local
User Management
Files: grafana-automation/ansible/operations/user/
- Individual CRUD operations or user_crud_workflow.yml
for complete workflow
Important: User management requires admin username/password authentication, not API keys. This is a Grafana API limitation.
Create Operations (operations/user/user_create.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- name: Create Grafana user
grafana.grafana.user:
login: "<username>"
password: ""
email: "<user@example.com>"
name: "<Full Name>"
grafana_url: ""
admin_name: ""
admin_password: ""
state: present
- name: Create multiple users
grafana.grafana.user:
login: ""
password: ""
email: ""
name: ""
grafana_url: ""
admin_name: ""
admin_password: ""
state: present
loop:
- { login: "<developer1>", password: "<dev_password>", name: "<Developer One>", email: "<dev1@company.com>" }
- { login: "<operator1>", password: "<ops_password>", name: "<Operator One>", email: "<ops1@company.com>" }
loop_control:
label: "Creating user "
Read Operations (operations/user/user_read.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
- name: Get organization users (with Bearer token)
uri:
url: "/api/org/users"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
status_code: [200, 403]
register: users_result
- name: Display organization users
debug:
msg: "Found organization users"
when: users_result.status == 200
- name: Show user details
debug:
msg: "User: (, Role: , Email: )"
loop: "{{ users_result.json if users_result.status == 200 else [] }}"
when: users_result.status == 200
- name: Access denied
debug:
msg: "Access denied - check service account permissions"
when: users_result.status == 403
- name: Get current user info
uri:
url: "/api/user"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
register: current_user
- name: Display current user
debug:
msg: "Current user: ()"
Update Operations (operations/user/user_update.yml
):
1
2
3
4
5
6
7
8
9
10
- name: Update user information
grafana.grafana.user:
grafana_url: ""
admin_name: ""
admin_password: ""
login: "<username>"
password: "<new_password>"
name: "<Updated Full Name>"
email: "<updated_user@example.com>"
state: present
Delete Operations (operations/user/user_delete.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- name: Delete single user
grafana.grafana.user:
grafana_url: ""
admin_name: ""
admin_password: ""
login: "<username>"
state: absent
ignore_errors: true
- name: Delete multiple users
grafana.grafana.user:
grafana_url: ""
admin_name: ""
admin_password: ""
login: ""
state: absent
loop:
- "<developer1>"
- "<operator1>"
ignore_errors: true
How to Run:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Create users
ansible-playbook -i inventory.ini operations/user/user_create.yml -e target_hosts=grafana_local
# Read users
ansible-playbook -i inventory.ini operations/user/user_read.yml -e target_hosts=grafana_local
# Update users
ansible-playbook -i inventory.ini operations/user/user_update.yml -e target_hosts=grafana_local
# Delete users
ansible-playbook -i inventory.ini operations/user/user_delete.yml -e target_hosts=grafana_local
# Complete CRUD workflow
ansible-playbook -i inventory.ini operations/user/user_crud_workflow.yml -e target_hosts=grafana_local
Cloud Services Management
Cloud API Key Management
Files: grafana-automation/ansible/operations/cloud_api_key/
- Individual CRUD operations for Cloud API keys
⚠️ Status: Currently NOT FUNCTIONAL - Cloud API key management endpoints are not available in Grafana Cloud API
Create Operations (operations/cloud_api_key/cloud_api_key_create.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
- name: Create Grafana Cloud API key
grafana.grafana.cloud_api_key:
name: "ansible-test-key"
role: "Editor"
org_slug: ""
existing_cloud_api_key: ""
fail_if_already_created: false
state: present
register: api_key_result
- name: Display created API key info
debug:
var: api_key_result
Read Operations (operations/cloud_api_key/cloud_api_key_read.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- name: Check available Cloud API endpoints
uri:
url: "https://grafana.com/api/instances/"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
register: instance_info
- name: Display Cloud API authentication status
debug:
msg: "✅ Cloud API Authentication: SUCCESS"
- name: Display available Cloud API endpoints
debug:
msg: ": "
loop: ""
- name: Display API key management limitation
debug:
msg: |
❌ API Key Management: NOT AVAILABLE via Cloud API
Note: API keys must be managed through:
1. Grafana instance UI: admin/api-keys
2. Instance API (if available): api/auth/keys
Cloud API is for instance-level management, not internal resource management.
Update Operations (operations/cloud_api_key/cloud_api_key_update.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
- name: Update Grafana Cloud API key (recreate with new role)
grafana.grafana.cloud_api_key:
name: "ansible-test-key"
role: "Admin"
org_slug: ""
existing_cloud_api_key: ""
fail_if_already_created: false
state: present
register: updated_api_key_result
- name: Display updated API key info
debug:
var: updated_api_key_result
Delete Operations (operations/cloud_api_key/cloud_api_key_delete.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
- name: Delete Grafana Cloud API key
grafana.grafana.cloud_api_key:
name: "ansible-test-key"
org_slug: ""
existing_cloud_api_key: ""
state: absent
register: delete_result
ignore_errors: true
- name: Display delete result
debug:
var: delete_result
How to Run:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Create API keys
ansible-playbook -i inventory.ini operations/cloud_api_key/cloud_api_key_create.yml -e target_hosts=grafana_cloud
# Status: ❌ FAILED - 404 "/orgs/<your-org-slug>/api-keys does not exist"
# Read API keys
ansible-playbook -i inventory.ini operations/cloud_api_key/cloud_api_key_read.yml -e target_hosts=grafana_cloud
# Status: ✅ SUCCESS - Shows available Cloud API endpoints and explains API key management limitations
# Update API keys
ansible-playbook -i inventory.ini operations/cloud_api_key/cloud_api_key_update.yml -e target_hosts=grafana_cloud
# Status: ❌ FAILED - 404 "/orgs/<your-org-slug>/api-keys does not exist"
# Delete API keys
ansible-playbook -i inventory.ini operations/cloud_api_key/cloud_api_key_delete.yml -e target_hosts=grafana_cloud
# Status: ❌ FAILED - "missing required arguments: role" (module parameter issue)
⚠️ Important Finding: Cloud API key management endpoints are not available in the current Grafana Cloud API. The /orgs/{org}/api-keys
endpoint returns 404 even though it’s listed in the organization’s links. This appears to be a limitation or unimplemented feature in Grafana Cloud.
Alternative: Manage Cloud API keys through the Grafana Cloud UI at https://grafana.com/
Cloud Plugin Management
Files: grafana-automation/ansible/operations/cloud_plugin/
- Individual CRUD operations for Cloud plugins
⚠️ Status: PARTIALLY FUNCTIONAL - Read operations work via instance API, but Ansible module has issues
Create Operations (operations/cloud_plugin/cloud_plugin_create.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
- name: Install Grafana Cloud plugin
grafana.grafana.cloud_plugin:
name: "grafana-github-datasource"
version: "1.0.14"
stack_slug: ""
cloud_api_key: ""
state: present
register: plugin_result
- name: Display plugin installation result
debug:
var: plugin_result
Read Operations (operations/cloud_plugin/cloud_plugin_read.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
- name: Get plugins from Grafana instance
uri:
url: "api/plugins"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
register: plugins_result
- name: Display plugins
debug:
var: plugins_result.json
Update Operations (operations/cloud_plugin/cloud_plugin_update.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
- name: Update Grafana Cloud plugin to specific version
grafana.grafana.cloud_plugin:
name: "grafana-github-datasource"
version: "1.0.14"
stack_slug: ""
cloud_api_key: ""
state: present
register: updated_plugin_result
- name: Display plugin update result
debug:
var: updated_plugin_result
Delete Operations (operations/cloud_plugin/cloud_plugin_delete.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
- name: Uninstall Grafana Cloud plugin
grafana.grafana.cloud_plugin:
name: "grafana-github-datasource"
stack_slug: ""
cloud_api_key: ""
state: absent
register: delete_result
ignore_errors: true
- name: Display plugin deletion result
debug:
var: delete_result
How to Run:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Install plugins
ansible-playbook -i inventory.ini operations/cloud_plugin/cloud_plugin_create.yml -e target_hosts=grafana_cloud
# Status: ❌ FAILED - KeyError: 'grafana_api_key' (module parameter issue)
# Read plugins
ansible-playbook -i inventory.ini operations/cloud_plugin/cloud_plugin_read.yml -e target_hosts=grafana_cloud
# Status: ✅ SUCCESS - Returns comprehensive list of all installed plugins from Grafana instance
# Update plugins
ansible-playbook -i inventory.ini operations/cloud_plugin/cloud_plugin_update.yml -e target_hosts=grafana_cloud
# Status: ❌ FAILED - KeyError: 'grafana_api_key' (module parameter issue)
# Delete plugins
ansible-playbook -i inventory.ini operations/cloud_plugin/cloud_plugin_delete.yml -e target_hosts=grafana_cloud
# Status: ❌ FAILED - 403 "You do not have permission to perform the requested action"
⚠️ Important Findings:
- Module Bug: The
grafana.grafana.cloud_plugin
module has a KeyError bug inpresent_cloud_plugin()
function (Issue #453) - Affected Operations: Create and update operations fail with
KeyError: 'grafana_api_key'
- Working Operations: Delete operations work but may have permission issues
- Read Operations: Work perfectly using direct instance API calls (
/api/plugins
) - Alternative: Manage plugins through Grafana Cloud UI or direct API calls until bug is fixed
Cloud Stack Management
Files: grafana-automation/ansible/operations/cloud_stack/
- Individual CRUD operations for Cloud stacks
⚠️ Status: LIMITED BY TIER - Module works correctly but Free tier restricts operations
Create Operations (operations/cloud_stack/cloud_stack_create.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- name: Create Grafana Cloud stack
grafana.grafana.cloud_stack:
name: "ansible-test-stack"
stack_slug: "ansible-test-stack"
cloud_api_key: ""
org_slug: ""
region: "us"
delete_protection: true
state: present
register: stack_result
- name: Display stack creation result
debug:
var: stack_result
Read Operations (operations/cloud_stack/cloud_stack_read.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
- name: Get Cloud stacks via API
uri:
url: "https://grafana.com/api/instances"
method: GET
headers:
Authorization: "Bearer "
return_content: yes
register: stacks_result
- name: Display Cloud stacks
debug:
var: stacks_result.json
Update Operations (operations/cloud_stack/cloud_stack_update.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- name: Update Grafana Cloud stack with custom URL
grafana.grafana.cloud_stack:
name: "ansible-test-stack"
stack_slug: "ansible-test-stack"
cloud_api_key: ""
org_slug: ""
region: "us"
url: "https://grafana.company.com"
delete_protection: false
state: present
register: updated_stack_result
- name: Display stack update result
debug:
var: updated_stack_result
Delete Operations (operations/cloud_stack/cloud_stack_delete.yml
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- name: Delete Grafana Cloud stack
grafana.grafana.cloud_stack:
name: "ansible-test-stack"
stack_slug: "ansible-test-stack"
cloud_api_key: ""
org_slug: ""
delete_protection: false
state: absent
register: delete_result
ignore_errors: true
- name: Display stack deletion result
debug:
var: delete_result
How to Run:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Create stacks
ansible-playbook -i inventory.ini operations/cloud_stack/cloud_stack_create.yml -e target_hosts=grafana_cloud
# Status: ❌ FAILED - "You have reached Maximum number of Cloud Stacks in your Org" (Free tier limit)
# Read stacks
ansible-playbook -i inventory.ini operations/cloud_stack/cloud_stack_read.yml -e target_hosts=grafana_cloud
# Status: ✅ SUCCESS - Returns detailed information about existing Cloud stacks
# Update stacks
ansible-playbook -i inventory.ini operations/cloud_stack/cloud_stack_update.yml -e target_hosts=grafana_cloud
# Status: ❌ FAILED - "You have reached Maximum number of Cloud Stacks in your Org" (Free tier limit)
# Delete stacks
ansible-playbook -i inventory.ini operations/cloud_stack/cloud_stack_delete.yml -e target_hosts=grafana_cloud
# Status: ❌ FAILED - 409 "Value must be id or slug: instanceId" (parameter validation issue)
⚠️ Important Findings:
- Free Tier Limitations: Grafana Cloud Free tier allows only 1 stack, preventing create/update operations
- Read Operations: Work perfectly and return comprehensive stack information including all service URLs
- Parameter Issues: Delete operation has validation issues with instance ID/slug parameters
- Functional Module: The
grafana.grafana.cloud_stack
module works correctly within tier limitations
⚠️ Testing Limitations:
- DO NOT TEST
cloud_stack_create.yml
on Free tier - will fail due to stack limit - DO NOT TEST
cloud_stack_delete.yml
on production - will delete your entire Grafana Cloud stack and all data - SAFE TO TEST: Only
cloud_stack_read.yml
for viewing existing stack information - Paid Tiers: Create/update operations should work on paid tiers with multiple stack allowances
Best Practices
- Use Ansible Vault for all secrets
- Group by environment (prod/staging/dev) for multiple instances
- Test with –check before applying
- Document jsonData sources in comments
- Use meaningful task names and loop labels
- Test on staging first before production
- Version control playbooks (vault files are safe to commit)
Frequently Asked Questions (FAQ)
Q: How do I fix “Authentication Failed” errors?
A: Check your API token validity and verify the Grafana URL is accessible. Ensure your API key has the required permissions for the operations you’re trying to perform.
Q: What should I do if I get “Module Not Found” errors?
A: Install the Grafana collection using:
1
ansible-galaxy collection install grafana.grafana
Q: How do I view encrypted vault files?
A: Use these commands:
1
2
3
4
5
# View encrypted vault file (requires password)
ansible-vault view vault.yml
# View with password file
ansible-vault view vault.yml --vault-password-file .vault_pass
Q: I get “vault.yml exists, please use ‘edit’ instead” - how to fix?
A: This means the file already exists. Use:
1
2
3
4
5
# Edit existing vault
ansible-vault edit vault.yml
# Or encrypt existing plain text file
ansible-vault encrypt vault.yml
Q: What does “input is not vault encrypted data” error mean?
A: The file is not encrypted. Check if it’s plain text and encrypt it:
1
2
3
4
5
6
7
8
9
# Check if file is plain text
cat vault.yml
# Encrypt existing plain text file
ansible-vault encrypt vault.yml
# If issues persist, recreate the vault
rm vault.yml
ansible-vault create vault.yml
Q: How do I securely delete vault files?
A: Use secure deletion methods:
1
2
3
4
5
6
7
8
9
# Remove encrypted vault file
rm vault.yml
# Or securely delete (overwrite before deletion)
shred -vfz -n 3 vault.yml # Linux
rm -P vault.yml # macOS
# Recreate vault with new credentials
ansible-vault create vault.yml
Q: Can I use this with managed Grafana services?
A: Yes! This guide works with self-hosted Grafana, Grafana Cloud, Azure Managed Grafana, and Amazon Managed Grafana. Simply update the grafana_url
to point to your managed instance endpoint.
Q: Do I need admin credentials for all operations?
A: No. Most operations (datasources, dashboards, folders) only require API keys. Admin username/password is only needed for user management operations.
Q: Which Grafana modules are fully functional?
A: The core modules (datasource, folder, dashboard, user, alert_contact_point, alert_notification_policy) are fully working. Cloud modules have limitations due to tier restrictions or API availability.
Troubleshooting
Common Issues
- Authentication Failed
- Check API token validity
- Verify Grafana URL is accessible
- Module Not Found
1
ansible-galaxy collection install grafana.grafana
Vault File Issues
View Encrypted Vault Content
1 2 3 4 5
# View encrypted vault file (requires password) ansible-vault view vault.yml # View with password file ansible-vault view vault.yml --vault-password-file .vault_pass
Error: “vault.yml exists, please use ‘edit’ instead”
1 2 3 4 5
# Edit existing vault ansible-vault edit vault.yml # Encrypt existing plain text file (for production use) ansible-vault encrypt vault.yml
Error: “input is not vault encrypted data”
1 2 3 4 5 6 7 8 9
# Check if file is plain text cat vault.yml # Encrypt existing plain text file (for production use) ansible-vault encrypt vault.yml # If above things don't work, then remove and re-create new encrypted vault rm vault.yml ansible-vault create vault.yml
Delete Vault File Securely
1 2 3 4 5 6 7 8 9
# Remove encrypted vault file rm vault.yml # Or securely delete (overwrite before deletion) shred -vfz -n 3 vault.yml # Linux rm -P vault.yml # macOS # Recreate vault with new credentials ansible-vault create vault.yml