134 lines
5.1 KiB
YAML
134 lines
5.1 KiB
YAML
|
---
|
||
|
- name: "Download grafana.net dashboards"
|
||
|
become: false
|
||
|
delegate_to: localhost
|
||
|
run_once: true
|
||
|
when: "grafana_dashboards | length > 0"
|
||
|
block:
|
||
|
- name: "Create local grafana dashboard directory"
|
||
|
ansible.builtin.tempfile:
|
||
|
state: directory
|
||
|
register: __tmp_dashboards
|
||
|
changed_when: false
|
||
|
|
||
|
- name: "Download grafana dashboard from grafana.net to local directory"
|
||
|
ansible.builtin.get_url:
|
||
|
url: "https://grafana.com/api/dashboards/{{ item.dashboard_id }}/revisions/{{ item.revision_id }}/download"
|
||
|
dest: "{{ __tmp_dashboards.path }}/{{ item.dashboard_id }}.json"
|
||
|
mode: "0644"
|
||
|
register: __download_dashboards
|
||
|
until: "__download_dashboards is succeeded"
|
||
|
retries: 5
|
||
|
delay: 2
|
||
|
changed_when: false
|
||
|
loop: "{{ grafana_dashboards }}"
|
||
|
|
||
|
# As noted in [1] an exported dashboard replaces the exporter's datasource
|
||
|
# name with a representative name, something like 'DS_GRAPHITE'. The name
|
||
|
# is different for each datasource plugin, but always begins with 'DS_'.
|
||
|
# In the rest of the data, the same name is used, but captured in braces,
|
||
|
# for example: '${DS_GRAPHITE}'.
|
||
|
#
|
||
|
# [1] http://docs.grafana.org/reference/export_import/#import-sharing-with-grafana-2-x-or-3-0
|
||
|
#
|
||
|
# The data structure looks (massively abbreviated) something like:
|
||
|
#
|
||
|
# "name": "DS_GRAPHITE",
|
||
|
# "datasource": "${DS_GRAPHITE}",
|
||
|
#
|
||
|
# If we import the downloaded dashboard verbatim, it will not automatically
|
||
|
# be connected to the data source like we want it. The Grafana UI expects
|
||
|
# us to do the final connection by hand, which we do not want to do.
|
||
|
# So, in the below task we ensure that we replace instances of this string
|
||
|
# with the data source name we want.
|
||
|
# To make sure that we're not being too greedy with the regex replacement
|
||
|
# of the data source to use for each dashboard that's uploaded, we make the
|
||
|
# regex match very specific by using the following:
|
||
|
#
|
||
|
# 1. Literal boundaries for " on either side of the match.
|
||
|
# 2. Non-capturing optional group matches for the ${} bits which may, or
|
||
|
# or may not, be there..
|
||
|
# 3. A case-sensitive literal match for DS .
|
||
|
# 4. A one-or-more case-sensitive match for the part that follows the
|
||
|
# underscore, with only A-Z, 0-9 and - or _ allowed.
|
||
|
#
|
||
|
# This regex can be tested and understood better by looking at the
|
||
|
# matches and non-matches in https://regex101.com/r/f4Gkvg/6
|
||
|
|
||
|
- name: "Set the correct data source name in the dashboard"
|
||
|
ansible.builtin.replace:
|
||
|
dest: "{{ __tmp_dashboards.path }}/{{ item.dashboard_id }}.json"
|
||
|
regexp: '"(?:\${)?DS_[A-Z0-9_-]+(?:})?"'
|
||
|
replace: '"{{ item.datasource }}"'
|
||
|
changed_when: false
|
||
|
loop: "{{ grafana_dashboards }}"
|
||
|
|
||
|
- name: "Import grafana dashboards via api"
|
||
|
community.grafana.grafana_dashboard:
|
||
|
grafana_url: "{{ grafana_api_url }}"
|
||
|
grafana_user: "{{ grafana_security.admin_user }}"
|
||
|
grafana_password: "{{ grafana_security.admin_password }}"
|
||
|
path: "{{ item }}"
|
||
|
message: "Updated by ansible role {{ ansible_role_name }}"
|
||
|
state: present
|
||
|
overwrite: true
|
||
|
no_log: "{{ 'false' if lookup('env', 'CI') else 'true' }}"
|
||
|
with_fileglob:
|
||
|
- "{{ __tmp_dashboards.path }}/*"
|
||
|
- "{{ grafana_dashboards_dir }}/*.json"
|
||
|
when: "not grafana_use_provisioning"
|
||
|
|
||
|
- name: "Import grafana dashboards through provisioning"
|
||
|
when: grafana_use_provisioning
|
||
|
block:
|
||
|
- name: "Create/Update dashboards file (provisioning)"
|
||
|
ansible.builtin.copy:
|
||
|
dest: "/etc/grafana/provisioning/dashboards/ansible.yml"
|
||
|
content: |
|
||
|
apiVersion: 1
|
||
|
providers:
|
||
|
- name: 'default'
|
||
|
orgId: 1
|
||
|
folder: ''
|
||
|
type: file
|
||
|
options:
|
||
|
path: "{{ grafana_data_dir }}/dashboards"
|
||
|
backup: false
|
||
|
owner: root
|
||
|
group: grafana
|
||
|
mode: "0640"
|
||
|
become: true
|
||
|
notify: restart_grafana
|
||
|
|
||
|
- name: "Register previously copied dashboards"
|
||
|
ansible.builtin.find:
|
||
|
paths: "{{ grafana_data_dir }}/dashboards"
|
||
|
hidden: true
|
||
|
patterns:
|
||
|
- "*.json"
|
||
|
register: __dashboards_present
|
||
|
when: grafana_provisioning_synced
|
||
|
|
||
|
- name: "Import grafana dashboards"
|
||
|
ansible.builtin.copy:
|
||
|
src: "{{ item }}"
|
||
|
dest: "{{ grafana_data_dir }}/dashboards/{{ item | basename }}"
|
||
|
mode: "0640"
|
||
|
with_fileglob:
|
||
|
- "{{ __tmp_dashboards.path }}/*"
|
||
|
- "{{ grafana_dashboards_dir }}/*.json"
|
||
|
become: true
|
||
|
register: __dashboards_copied
|
||
|
notify: "provisioned dashboards changed"
|
||
|
|
||
|
- name: "Remove dashboards not present on deployer machine (synchronize)"
|
||
|
ansible.builtin.file:
|
||
|
path: "{{ item }}"
|
||
|
state: absent
|
||
|
loop: "{{ __dashboards_present_list | difference(__dashboards_copied_list) }}"
|
||
|
become: true
|
||
|
when: grafana_provisioning_synced
|
||
|
vars:
|
||
|
__dashboards_present_list: "{{ __dashboards_present | json_query('files[*].path') | default([]) }}"
|
||
|
__dashboards_copied_list: "{{ __dashboards_copied | json_query('results[*].dest') | default([]) }}"
|