Merge pull request #26 from corvus-migratorius/add-grafana

Add grafana
This commit is contained in:
Fogucoco
2025-12-12 16:21:51 +03:00
committed by GitHub
24 changed files with 3367 additions and 1 deletions

View File

@@ -82,6 +82,10 @@ jobs:
run: ansible-galaxy collection install community.general
shell: micromamba-shell {0}
- name: "Install community.grafana collection"
run: ansible-galaxy collection install community.grafana
shell: micromamba-shell {0}
- name: "Run Molecule tests"
if: ${{ matrix.role != '__no_role__' }}
working-directory: ${{ matrix.role }}

View File

@@ -7,6 +7,7 @@
- [alertmanager](roles/alertmanager/README.md)
- [dnsmasq](roles/dnsmasq/README.md)
- [grafana](roles/grafana/README.md)
- [mount_device](roles/mount_device/README.md)
- [prometheus](roles/prometheus/README.md)
- [ufw](roles/ufw/README.md)

View File

@@ -1,7 +1,7 @@
---
namespace: genlab
name: common
version: 0.7.0
version: 0.8.0
readme: README.md
authors:
- Alexander Gorelyshev (corvus-migratorius@proton.me)

107
roles/grafana/README.md Normal file
View File

@@ -0,0 +1,107 @@
genlab.grafana
=========
This ansible role installs [Grafana](https://github.com/grafana/grafana) - the open-source platform for monitoring and observability. It can produce charts, graphs, and alerts for the web when connected to supported data sources.
This role installs and configures Grafana from a binary distribution. It also:
- Uploads custom dashboards
- Installs plugins
- Imports public dashboards and data sources
- Allows admin password changes
Supports user creation
Grafana service requires an environment file at startup, where you can set custom paths for logs (`grafana_log_dir`), data (`grafana_data_dir`), and plugins (`grafana_plugins_dir`). This allows flexible control over Grafana's data storage.
Requirements
------------
You need `community.grafana` module.
Role Variables
--------------
```
grafana_user: "grafana" # user name
grafana_group: "grafana" # group name
grafana_version: 11.5.0 # version
grafana_port: 3000 # port
# Directory paths
grafana_dashboard_dir: "/tmp/grafana/dashboards" # where to copy dashboards from source
grafana_plugins_dir: "/var/lib/grafana/plugins" # where to store plugins on target
grafana_datasource_dir: "/etc/grafana/provisioning/datasources" # where to store data sources on target
grafana_log_dir: "/var/log/grafana" # where to write logs
grafana_data_dir: "/var/lib/grafana" # where to store Grafana DB
# Optional configurations
grafana_users: [] # array of user names, passwords, and statuses
grafana_plugins: [] # array of plugins to install
grafana_public_dashboards: [] # array of public dashboards to import
# Admin credentials
admin_api_username: "secret" # Grafana admin username
admin_api_password: "secret" # Grafana admin password
# Source paths
dashboard_source_path: "mydir/dashboards" # path to dashboards on source server
datasource_source_path: "mydir/datasources" # path to data sources on source server
```
Dependencies
------------
None
Example Playbook
----------------
```yaml
---
- name: Converge
hosts: all
vars:
grafana_users:
- name: "test"
user_login: "test"
user_password: "test"
user_email: "test@mail.ru"
is_admin: false
grafana_plugins:
version: 2.1.8
- name: aceiot-svg-panel
version: 0.1.5
grafana_public_dashboards:
- name: Node Full Exporter
id: 1860
revision: 36
vars_files:
- secrets/admin_cred.yml
roles:
- role: genlab.grafana
grafana_version: 11.5.0
admin_api_username: "{{ grafana.admin_api_username }}"
admin_api_password: "{{ grafana.admin_api_password }}"
users: "{{ grafana_users }}"
plugins: "{{ grafana_plugins }}"
public_dashboards: "{{ grafana_public_dashboards }}"
dashboard_source_path: "molecule/default/dashboards"
datasource_source_path: "molecule/default/datasources"
grafana_log_dir: "/opt/grafana/data"
grafana_data_dir: "/opt/grafana/lib"
```
License
-------
BSD
Author Information
------------------
corvus-migratorius@proton.me

View File

@@ -0,0 +1,10 @@
---
grafana_user: "grafana"
grafana_group: "grafana"
grafana_version: 11.5.0
grafana_port: 3000
grafana_dashboard_dir: "/tmp/grafana/dashboards"
grafana_plugins_dir: "/var/lib/grafana/plugins"
grafana_datasource_dir: "/etc/grafana/provisioning/datasources"
grafana_log_dir: "/var/log/grafana"
grafana_data_dir: "/var/lib/grafana"

View File

@@ -0,0 +1,7 @@
---
- name: "(Re)start and enable Grafana"
ansible.builtin.systemd_service:
name: grafana-server
state: restarted
enabled: true
daemon_reload: true

View File

@@ -0,0 +1,17 @@
---
galaxy_info:
role_name: "grafana"
namespace: genlab
author: "Alexander Gorelyshev"
company: "Genlab, LLC"
description: ""
license: "MIT"
min_ansible_version: "2.1"
platforms:
- name: "Ubuntu"
versions: ["focal", "jammy", "noble"]
galaxy_tags: []
dependencies: []

View File

@@ -0,0 +1,44 @@
---
- name: Converge
hosts: all
vars:
grafana_users:
- name: "test"
user_login: "test"
# kics-scan ignore-line
user_password: "test"
user_email: "test@mail.ru"
is_admin: false
- name: "test2"
user_login: "test2"
# kics-scan ignore-line
user_password: "test2"
user_email: "test2@mail.ru"
is_admin: true
grafana_plugins:
- name: grafana-metricsdrilldown-app
version: 1.0.0
- name: grafana-clock-panel
version: 2.1.8
- name: aceiot-svg-panel
version: 0.1.5
grafana_public_dashboards:
- name: Node Full Exporter
id: 1860
revision: 36
vars_files:
- secrets/admin_cred.yml
roles:
# kics-scan ignore-block
- role: genlab.common.grafana
grafana_version: 11.5.0
admin_api_username: "{{ grafana.admin_api_username }}"
admin_api_password: "{{ grafana.admin_api_password }}"
users: "{{ grafana_users }}"
plugins: "{{ grafana_plugins }}"
public_dashboards: "{{ grafana_public_dashboards }}"
dashboard_source_path: "molecule/default/dashboards"
datasource_source_path: "molecule/default/datasources"
grafana_log_dir: "/opt/grafana/data"
grafana_data_dir: "/opt/grafana/lib"

View File

@@ -0,0 +1,700 @@
{
"__inputs": [
{
"name": "DS_PROMETHEUS",
"label": "Prometheus",
"description": "",
"type": "datasource",
"pluginId": "prometheus",
"pluginName": "Prometheus"
}
],
"__requires": [
{
"type": "panel",
"id": "bargauge",
"name": "Bar gauge",
"version": ""
},
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "7.1.5"
},
{
"type": "panel",
"id": "graph",
"name": "Graph",
"version": ""
},
{
"type": "datasource",
"id": "prometheus",
"name": "Prometheus",
"version": "1.0.0"
},
{
"type": "panel",
"id": "stat",
"name": "Stat",
"version": ""
},
{
"type": "panel",
"id": "table",
"name": "Table",
"version": ""
}
],
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 29,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"decimals": 0,
"mappings": [],
"min": 0,
"noValue": "0",
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "#EAB839",
"value": 1
}
]
},
"unit": "none"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 15,
"x": 0,
"y": 0
},
"id": 4,
"options": {
"displayMode": "gradient",
"minVizHeight": 10,
"minVizWidth": 0,
"orientation": "horizontal",
"reduceOptions": {
"calcs": [
"last"
],
"fields": "",
"values": false
},
"showUnfilled": true,
"valueMode": "color"
},
"pluginVersion": "10.1.5",
"targets": [
{
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=~\"fail|error\" } > 0) by (namespace)",
"instant": true,
"interval": "",
"legendFormat": "{{namespace}}",
"refId": "A"
}
],
"title": "Failing Policies by Namespace",
"type": "bargauge"
},
{
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"decimals": 0,
"mappings": [],
"min": 0,
"noValue": "0",
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "#EAB839",
"value": 3
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 9,
"x": 15,
"y": 0
},
"id": 5,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "center",
"orientation": "vertical",
"reduceOptions": {
"calcs": [
"last"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "10.1.5",
"targets": [
{
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=~\"fail|error\" } > 0) by (status)",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
"legendFormat": "{{ status }}",
"refId": "A"
}
],
"title": "Failing ClusterPolicies",
"type": "stat"
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 10,
"w": 24,
"x": 0,
"y": 8
},
"hiddenSeries": false,
"id": 11,
"legend": {
"alignAsTable": true,
"avg": false,
"current": true,
"hideEmpty": true,
"hideZero": true,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null as zero",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.1.5",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=~\"fail|error\" } > 0) by (policy)",
"interval": "",
"legendFormat": "{{ policy }}",
"refId": "A"
},
{
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=~\"fail|error\" } > 0) by (policy)",
"interval": "",
"legendFormat": "{{ policy }}",
"refId": "B"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Failing Policies Graph",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"decimals": 0,
"format": "short",
"logBase": 1,
"min": "0",
"show": true
},
{
"format": "short",
"logBase": 1,
"show": true
}
],
"yaxis": {
"align": false
}
},
{
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"custom": {
"cellOptions": {
"type": "auto"
},
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 10,
"w": 24,
"x": 0,
"y": 18
},
"id": 7,
"options": {
"cellHeight": "sm",
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "10.1.5",
"targets": [
{
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=~\"fail|error\" }) by (namespace,policy,rule,kind,name,status,category,severity,source)",
"format": "table",
"instant": true,
"interval": "",
"legendFormat": "{{namespace}}: {{ policy }}",
"refId": "A"
}
],
"title": "Failing PolicyRules",
"transformations": [
{
"id": "organize",
"options": {
"excludeByName": {
"Time": true,
"Value": true
},
"indexByName": {
"category": 1,
"kind": 4,
"name": 5,
"namespace": 3,
"policy": 6,
"rule": 7,
"severity": 2,
"source": 0,
"status": 8
},
"renameByName": {
"namespace": "namespace"
}
}
}
],
"type": "table"
},
{
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"custom": {
"cellOptions": {
"type": "auto"
},
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 10,
"w": 24,
"x": 0,
"y": 28
},
"id": 9,
"options": {
"cellHeight": "sm",
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true
},
"pluginVersion": "10.1.5",
"targets": [
{
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=~\"fail|error\" }) by (policy,rule,kind,name,status,category,severity,source)",
"format": "table",
"instant": true,
"interval": "",
"legendFormat": "{{ kind }}: {{ name }} - {{ policy }}",
"refId": "A"
}
],
"title": "Failing ClusterPolicyRules",
"transformations": [
{
"id": "organize",
"options": {
"excludeByName": {
"Time": true,
"Value": true,
"__name__": true,
"container": true,
"endpoint": true,
"instance": true,
"job": true,
"namespace": true,
"pod": true,
"report": true,
"service": true
},
"indexByName": {
"category": 1,
"kind": 3,
"name": 4,
"policy": 5,
"rule": 6,
"severity": 2,
"source": 0,
"status": 7
},
"renameByName": {}
}
}
],
"type": "table"
}
],
"refresh": "",
"schemaVersion": 38,
"style": "dark",
"tags": [
"Policy Reporter"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "Prometheus",
"value": "prometheus"
},
"hide": 0,
"includeAll": false,
"label": "Datasource",
"multi": false,
"name": "DS_PROMETHEUS",
"options": [],
"query": "prometheus",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
},
{
"allValue": ".*",
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, policy)",
"hide": 0,
"includeAll": true,
"label": "Policy",
"multi": true,
"name": "policy",
"options": [],
"query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, policy)",
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 5,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allValue": ".*",
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, category)",
"hide": 0,
"includeAll": true,
"label": "Category",
"multi": true,
"name": "category",
"options": [],
"query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, category)",
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 5,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allValue": ".*",
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, severity)",
"hide": 0,
"includeAll": true,
"label": "Severity",
"multi": true,
"name": "severity",
"options": [],
"query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, severity)",
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 5,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allValue": ".*",
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values({__name__= \"policy_report_result\", status=~\"fail|error\"}, namespace)",
"hide": 0,
"includeAll": true,
"label": "Namespace",
"multi": true,
"name": "namespace",
"options": [],
"query": "label_values({__name__= \"policy_report_result\", status=~\"fail|error\"}, namespace)",
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 5,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allValue": ".*",
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, kind)",
"hide": 0,
"includeAll": true,
"label": "Kind",
"multi": true,
"name": "kind",
"options": [],
"query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, kind)",
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 5,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allValue": ".*",
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, source)",
"hide": 0,
"includeAll": true,
"label": "Source",
"multi": true,
"name": "source",
"options": [],
"query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, source)",
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 5,
"tagValuesQuery": "",
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-30m",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "PolicyReports",
"uid": "ZkwXrUMnk",
"version": 1,
"gnetId": 13968
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
apiVersion: 1
datasources:
- name: Loki
type: loki
access: proxy
basicAuth: false
basicAuthPassword: false
url: http://localhost:3100
jsonData:
maxLines: 1000
httpHeaderName1: "Authorization"
secureJsonData:
httpHeaderValue1: "Bearer your_token_here"
version: 1
editable: false

View File

@@ -0,0 +1,50 @@
# config file version
apiVersion: 1
# list of datasources that should be deleted from the database
# deleteDatasources:
# - name: Prometheus
# orgId: 1
# list of datasources to insert/update depending
# whats available in the database
datasources:
# <string, required> name of the datasource. Required
- name: Prometheus
# <string, required> datasource type. Required
type: prometheus
# <string, required> access mode. direct or proxy. Required
access: proxy
# <int> org id. will default to orgId 1 if not specified
orgId: 1
# <string> url
url: http://localhost:9090
# <string> database password, if used
password:
# <string> database user, if used
user:
# <string> database name, if used
database:
# <bool> enable/disable basic auth
basicAuth: false
# <string> basic auth username, if used
basicAuthUser:
# <string> basic auth password, if used
basicAuthPassword:
# <bool> enable/disable with credentials headers
withCredentials:
# <bool> mark as default datasource. Max one per org
isDefault: true
# <map> fields that will be converted to json and stored in json_data
jsonData:
graphiteVersion: "1.1"
tlsAuth: false
tlsAuthWithCACert: false
# <string> json object of data that will be encrypted.
secureJsonData:
tlsCACert: "..."
tlsClientCert: "..."
tlsClientKey: "..."
version: 1
# <bool> allow users to edit datasources from the UI.
editable: true

View File

@@ -0,0 +1,29 @@
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: ubuntu
image: geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2404}-ansible:latest
pre_build_image: true
command: ${MOLECULE_DOCKER_COMMAND:-""}
published_ports:
- 127.0.0.1:3001:3000
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
privileged: true
provisioner:
name: ansible
verifier:
name: ansible
lint: |
set -e
yamllint .
ansible-lint .

View File

@@ -0,0 +1,3 @@
grafana:
admin_api_username: "admin"
admin_api_password: "changme23"

View File

@@ -0,0 +1,41 @@
---
- name: Verify
hosts: all
gather_facts: false
any_errors_fatal: true
vars_files:
- admin_cred.yml
tasks:
- name: "Include default vars"
ansible.builtin.include_vars:
dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults/"
extensions: ['yml']
- name: "Check if Grafana is installed"
changed_when: false
ansible.builtin.command: "grafana-server -v"
register: grafana_installed_version
- name: "Check Grafana version"
ansible.builtin.assert:
that: "grafana_installed_version.stdout is regex('{{ grafana_version }}')"
success_msg: "grafana version {{ grafana_version }} is installed and working"
fail_msg: "grafana version {{ grafana_version }} is not installed or not working correctly"
# kics-scan ignore-block
- name: "Check if Grafana login page is reachable"
ansible.builtin.uri:
url: "http://localhost:{{ grafana_port }}/api/health"
return_content: true
status_code: 200
method: GET
body_format: json
register: grafana_health
- name: "Debug Grafana health status"
ansible.builtin.assert:
that: grafana_health.json.database == "ok"
success_msg: "Grafana is healthy"
fail_msg: "Grafana is not healthy"

View File

@@ -0,0 +1,40 @@
---
- name: "Create dashboard directory"
ansible.builtin.file:
path: "{{ grafana_dashboard_dir }}"
state: directory
owner: "{{ grafana_user }}"
group: "{{ grafana_group }}"
mode: "0755"
- name: "Copy dashboard files from source to target"
ansible.builtin.copy:
src: "{{ item }}"
dest: "{{ grafana_dashboard_dir }}/{{ item | basename }}"
mode: "0644"
owner: "{{ grafana_user }}"
group: "{{ grafana_group }}"
with_fileglob:
- "{{ dashboard_source_path }}/*.json"
- name: "Import Grafana dashboards to Grafana"
community.grafana.grafana_dashboard:
grafana_url: "http://127.0.0.1:{{ grafana_port }}"
url_username: "{{ admin_api_username }}"
url_password: "{{ admin_api_password }}"
state: present
commit_message: Updated by ansible
overwrite: false
path: "{{ grafana_dashboard_dir }}/{{ item | basename }}"
with_fileglob:
- "{{ dashboard_source_path }}/*.json"
- name: "Run | reload Grafana provisioned dashboard configurations"
ansible.builtin.uri:
# kics-scan ignore-line
url: "http://127.0.0.1:{{ grafana_port }}/api/admin/provisioning/dashboards/reload"
method: POST
force_basic_auth: true
user: "{{ admin_api_username }}"
password: "{{ admin_api_password }}"
status_code: 200

View File

@@ -0,0 +1,28 @@
---
- name: "Create datasource directory"
ansible.builtin.file:
path: "{{ grafana_datasource_dir }}"
state: directory
owner: "{{ grafana_user }}"
group: "{{ grafana_group }}"
mode: "0755"
- name: "Configure | provision datasources for Grafana"
ansible.builtin.copy:
src: "{{ datasource_source_path }}/{{ item | basename }}"
dest: "{{ grafana_datasource_dir }}/{{ item | basename }}"
owner: "{{ grafana_user }}"
group: "{{ grafana_group }}"
mode: "0660"
with_fileglob:
"{{ datasource_source_path }}/*.y*ml"
- name: "Run | reload Grafana datasource provisioned configurations"
ansible.builtin.uri:
# kics-scan ignore-line
url: "http://127.0.0.1:{{ grafana_port }}/api/admin/provisioning/datasources/reload"
method: POST
force_basic_auth: true
user: "{{ admin_api_username }}"
password: "{{ admin_api_password }}"
status_code: 200

View File

@@ -0,0 +1,11 @@
---
- name: "Import public dashboard - '{{ public_dashboard.name }}''"
community.grafana.grafana_dashboard:
grafana_url: "http://127.0.0.1:{{ grafana_port }}"
state: "{{ public_dashboard.state | default('present') }}"
overwrite: false
dashboard_id: "{{ public_dashboard.id }}"
dashboard_revision: "{{ public_dashboard.revision }}"
commit_message: "Add public dashboard '{{ public_dashboard.name }}''"
url_username: "{{ admin_api_username }}"
url_password: "{{ admin_api_password }}"

View File

@@ -0,0 +1,78 @@
---
- name: "Create Grafana system group"
ansible.builtin.group:
name: grafana
system: true
state: present
- name: "Create Grafana system user"
ansible.builtin.user:
name: grafana
group: grafana
system: true
shell: "/sbin/nologin"
create_home: false
state: present
- name: "Install Grafana deb package"
block:
- name: "Check Grafana version"
changed_when: false
ansible.builtin.command:
cmd: "grafana-server --version"
register: grafana_ver
- name: "Assert version correctness"
ansible.builtin.assert:
that: "grafana_ver.stdout is regex('{{ grafana_version }}')"
success_msg: "grafana version {{ grafana_version }} is installed and working"
fail_msg: "grafana version {{ grafana_version }} is not installed or not working correctly"
rescue:
- name: "Ensure that directories exist"
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ grafana_user }}"
group: "{{ grafana_group }}"
mode: '0775'
with_items:
- "{{ grafana_log_dir }}"
- "{{ grafana_data_dir }}"
- "{{ grafana_plugins_dir }}"
- name: "Download Grafana DEB package"
ansible.builtin.get_url:
url: "https://dl.grafana.com/oss/release/grafana_{{ grafana_version }}_amd64.deb"
dest: "/tmp/grafana-{{ grafana_version }}_amd64.deb"
owner: "{{ grafana_user }}"
group: "{{ grafana_group }}"
mode: "0644"
register: grafana_package_tmp
- name: "Install DEB package"
notify: "(Re)start and enable Grafana"
ansible.builtin.apt:
deb: "{{ grafana_package_tmp.dest }}"
state: present
update_cache: true
- name: "Cleanup downloaded file"
ansible.builtin.file:
path: "/tmp/grafana-{{ grafana_version }}_amd64.deb"
state: absent
- name: "Create env file for systemd service unit"
notify: "(Re)start and enable Grafana"
ansible.builtin.template:
src: grafana-server.env.j2
dest: "{{ item }}"
owner: "{{ grafana_user }}"
group: "{{ grafana_group }}"
mode: "0660"
with_items:
- "/etc/default/grafana-server"
- "/etc/default/grafana"
- name: "Flush handlers"
ansible.builtin.meta: "flush_handlers"

View File

@@ -0,0 +1,39 @@
---
- name: "Include grafana installation tasks"
ansible.builtin.include_tasks: install.yml
- name: "Wait for the Grafana server to become available"
ansible.builtin.wait_for:
host: "127.0.0.1"
port: "{{ grafana_port }}"
state: started
delay: 10
- name: "Include user creation tasks"
when: users is defined
loop: "{{ users }}"
loop_control:
loop_var: user
ansible.builtin.include_tasks: user.yml
- name: "Configure custom dashboards"
when: dashboard_source_path is defined
ansible.builtin.include_tasks: dashboards.yml
- name: "Configure public dashboards"
when: public_dashboards is defined
loop: "{{ public_dashboards }}"
loop_control:
loop_var: public_dashboard
ansible.builtin.include_tasks: import_pub_dashboard.yml
- name: "Configure plugins"
when: plugins is defined
loop: "{{ plugins }}"
loop_control:
loop_var: plugin
ansible.builtin.include_tasks: plugins.yml
- name: "Configure datasources"
when: datasource_source_path is defined
ansible.builtin.include_tasks: datasources.yml

View File

@@ -0,0 +1,16 @@
---
- name: "Create plugin directory"
ansible.builtin.file:
path: "{{ grafana_plugins_dir }}"
state: directory
owner: "{{ grafana_user }}"
group: "{{ grafana_group }}"
mode: "0755"
- name: "Install Grafana plugins"
community.grafana.grafana_plugin:
name: "{{ plugin.name }}"
version: "{{ plugin.version }}"
grafana_plugins_dir: "{{ grafana_plugins_dir }}"
state: "{{ plugin.state | default('present') }}"
notify: "(Re)start and enable Grafana"

View File

@@ -0,0 +1,19 @@
---
- name: "Reset default admin password"
ansible.builtin.command: >
grafana-cli admin reset-admin-password "{{ admin_api_password }}"
no_log: true
changed_when: false
- name: "Create | update a Grafana user"
community.grafana.grafana_user:
url: "http://127.0.0.1:{{ grafana_port }}"
url_username: "{{ admin_api_username }}"
url_password: "{{ admin_api_password }}"
name: "{{ user.name }}"
email: "{{ user.user_email }}"
login: "{{ user.user_login }}"
password: "{{ user.user_password }}"
is_admin: "{{ user.is_admin | default(false) }}"
state: present

View File

@@ -0,0 +1,24 @@
GRAFANA_USER=grafana
GRAFANA_GROUP=grafana
GRAFANA_HOME=/usr/share/grafana
LOG_DIR={{ grafana_log_dir }}
DATA_DIR={{ grafana_data_dir }}
MAX_OPEN_FILES=10000
CONF_DIR=/etc/grafana
CONF_FILE=/etc/grafana/grafana.ini
RESTART_ON_UPGRADE=true
PLUGINS_DIR={{ grafana_plugins_dir }}
PROVISIONING_CFG_DIR=/etc/grafana/provisioning
# Only used on systemd systems
PID_FILE_DIR=/run/grafana

View File

@@ -0,0 +1 @@
---