|
1 | 1 | --- |
2 | | -- name: Empty local grafana dashboard directory |
3 | | - become: false |
4 | | - file: |
5 | | - path: /tmp/dashboards |
6 | | - state: absent |
| 2 | +- become: false |
7 | 3 | delegate_to: localhost |
8 | 4 | run_once: true |
9 | | - check_mode: false |
10 | | - changed_when: false |
11 | | - when: grafana_use_provisioning and grafana_provisioning_synced |
| 5 | + block: |
| 6 | + - name: Create local grafana dashboard directory |
| 7 | + tempfile: |
| 8 | + state: directory |
| 9 | + register: _tmp_dashboards |
| 10 | + changed_when: false |
| 11 | + check_mode: false |
12 | 12 |
|
13 | | -- name: Create local grafana dashboard directories |
14 | | - become: false |
15 | | - file: |
16 | | - path: /tmp/dashboards |
17 | | - state: directory |
18 | | - mode: 0755 |
19 | | - delegate_to: localhost |
20 | | - run_once: true |
21 | | - check_mode: false |
22 | | - changed_when: false |
23 | | - |
24 | | -# - name: download grafana dashboard from grafana.net to local folder |
25 | | -# become: false |
26 | | -# get_url: |
27 | | -# url: "https://grafana.com/api/dashboards/{{ item.dashboard_id }}/revisions/{{ item.revision_id }}/download" |
28 | | -# dest: "/tmp/dashboards/{{ item.dashboard_id }}.json" |
29 | | -# register: _download_dashboards |
30 | | -# until: _download_dashboards is succeeded |
31 | | -# retries: 5 |
32 | | -# delay: 2 |
33 | | -# delegate_to: localhost |
34 | | -# run_once: true |
35 | | -# changed_when: false |
36 | | -# with_items: "{{ grafana_dashboards }}" |
37 | | -# when: grafana_dashboards | length > 0 |
| 13 | + # Use curl to solve issue #77 |
| 14 | + - name: download grafana dashboard from grafana.net to local directory |
| 15 | + command: > |
| 16 | + curl --fail --compressed |
| 17 | + https://grafana.com/api/dashboards/{{ item.dashboard_id }}/revisions/{{ item.revision_id }}/download |
| 18 | + -o {{ _tmp_dashboards.path }}/{{ item.dashboard_id }}.json |
| 19 | + args: |
| 20 | + creates: "{{ _tmp_dashboards.path }}/{{ item.dashboard_id }}.json" |
| 21 | + warn: false |
| 22 | + register: _download_dashboards |
| 23 | + until: _download_dashboards is succeeded |
| 24 | + retries: 5 |
| 25 | + delay: 2 |
| 26 | + with_items: "{{ grafana_dashboards }}" |
| 27 | + when: grafana_dashboards | length > 0 |
| 28 | + changed_when: false |
| 29 | + check_mode: false |
| 30 | + tags: |
| 31 | + - skip_ansible_lint |
38 | 32 |
|
39 | | -# Use curl to solve issue #77 |
40 | | -- name: download grafana dashboard from grafana.net to local directory |
41 | | - become: false |
42 | | - command: "curl --fail --compressed https://grafana.com/api/dashboards/{{ item.dashboard_id }}/revisions/{{ item.revision_id }}/download -o /tmp/dashboards/{{ item.dashboard_id }}.json" # noqa 204 |
43 | | - args: |
44 | | - creates: "/tmp/dashboards/{{ item.dashboard_id }}.json" |
45 | | - warn: false |
46 | | - register: _download_dashboards |
47 | | - until: _download_dashboards is succeeded |
48 | | - retries: 5 |
49 | | - delay: 2 |
50 | | - delegate_to: localhost |
51 | | - run_once: true |
52 | | - with_items: "{{ grafana_dashboards }}" |
53 | | - when: grafana_dashboards | length > 0 |
54 | | - tags: |
55 | | - - skip_ansible_lint |
56 | | - check_mode: false |
| 33 | + # As noted in [1] an exported dashboard replaces the exporter's datasource |
| 34 | + # name with a representative name, something like 'DS_GRAPHITE'. The name |
| 35 | + # is different for each datasource plugin, but always begins with 'DS_'. |
| 36 | + # In the rest of the data, the same name is used, but captured in braces, |
| 37 | + # for example: '${DS_GRAPHITE}'. |
| 38 | + # |
| 39 | + # [1] http://docs.grafana.org/reference/export_import/#import-sharing-with-grafana-2-x-or-3-0 |
| 40 | + # |
| 41 | + # The data structure looks (massively abbreviated) something like: |
| 42 | + # |
| 43 | + # "name": "DS_GRAPHITE", |
| 44 | + # "datasource": "${DS_GRAPHITE}", |
| 45 | + # |
| 46 | + # If we import the downloaded dashboard verbatim, it will not automatically |
| 47 | + # be connected to the data source like we want it. The Grafana UI expects |
| 48 | + # us to do the final connection by hand, which we do not want to do. |
| 49 | + # So, in the below task we ensure that we replace instances of this string |
| 50 | + # with the data source name we want. |
| 51 | + # To make sure that we're not being too greedy with the regex replacement |
| 52 | + # of the data source to use for each dashboard that's uploaded, we make the |
| 53 | + # regex match very specific by using the following: |
| 54 | + # |
| 55 | + # 1. Literal boundaries for " on either side of the match. |
| 56 | + # 2. Non-capturing optional group matches for the ${} bits which may, or |
| 57 | + # or may not, be there.. |
| 58 | + # 3. A case-sensitive literal match for DS . |
| 59 | + # 4. A one-or-more case-sensitive match for the part that follows the |
| 60 | + # underscore, with only A-Z, 0-9 and - or _ allowed. |
| 61 | + # |
| 62 | + # This regex can be tested and understood better by looking at the |
| 63 | + # matches and non-matches in https://regex101.com/r/f4Gkvg/6 |
57 | 64 |
|
58 | | -# As noted in [1] an exported dashboard replaces the exporter's datasource |
59 | | -# name with a representative name, something like 'DS_GRAPHITE'. The name |
60 | | -# is different for each datasource plugin, but always begins with 'DS_'. |
61 | | -# In the rest of the data, the same name is used, but captured in braces, |
62 | | -# for example: '${DS_GRAPHITE}'. |
63 | | -# |
64 | | -# [1] http://docs.grafana.org/reference/export_import/#import-sharing-with-grafana-2-x-or-3-0 |
65 | | -# |
66 | | -# The data structure looks (massively abbreviated) something like: |
67 | | -# |
68 | | -# "name": "DS_GRAPHITE", |
69 | | -# "datasource": "${DS_GRAPHITE}", |
70 | | -# |
71 | | -# If we import the downloaded dashboard verbatim, it will not automatically |
72 | | -# be connected to the data source like we want it. The Grafana UI expects |
73 | | -# us to do the final connection by hand, which we do not want to do. |
74 | | -# So, in the below task we ensure that we replace instances of this string |
75 | | -# with the data source name we want. |
76 | | -# To make sure that we're not being too greedy with the regex replacement |
77 | | -# of the data source to use for each dashboard that's uploaded, we make the |
78 | | -# regex match very specific by using the following: |
79 | | -# |
80 | | -# 1. Literal boundaries for " on either side of the match. |
81 | | -# 2. Non-capturing optional group matches for the ${} bits which may, or |
82 | | -# or may not, be there.. |
83 | | -# 3. A case-sensitive literal match for DS . |
84 | | -# 4. A one-or-more case-sensitive match for the part that follows the |
85 | | -# underscore, with only A-Z, 0-9 and - or _ allowed. |
86 | | -# |
87 | | -# This regex can be tested and understood better by looking at the |
88 | | -# matches and non-matches in https://regex101.com/r/f4Gkvg/6 |
| 65 | + - name: Set the correct data source name in the dashboard |
| 66 | + replace: |
| 67 | + dest: "{{ _tmp_dashboards.path }}/{{ item.dashboard_id }}.json" |
| 68 | + regexp: '"(?:\${)?DS_[A-Z0-9_-]+(?:})?"' |
| 69 | + replace: '"{{ item.datasource }}"' |
| 70 | + changed_when: false |
| 71 | + with_items: "{{ grafana_dashboards }}" |
| 72 | + when: grafana_dashboards | length > 0 |
89 | 73 |
|
90 | | -- name: Set the correct data source name in the dashboard |
91 | | - become: false |
92 | | - replace: |
93 | | - dest: "/tmp/dashboards/{{ item.dashboard_id }}.json" |
94 | | - regexp: '"(?:\${)?DS_[A-Z0-9_-]+(?:})?"' |
95 | | - replace: '"{{ item.datasource }}"' |
96 | | - delegate_to: localhost |
97 | | - run_once: true |
98 | | - changed_when: false |
99 | | - with_items: "{{ grafana_dashboards }}" |
100 | | - when: grafana_dashboards | length > 0 |
101 | | - |
102 | | -- name: copy local grafana dashboards |
103 | | - become: false |
104 | | - copy: |
105 | | - src: "{{ item }}" |
106 | | - dest: "/tmp/dashboards/{{ item | basename }}" |
107 | | - with_fileglob: |
108 | | - - "{{ grafana_dashboards_dir }}/*.json" |
109 | | - delegate_to: localhost |
110 | | - run_once: true |
111 | | - changed_when: false |
112 | | - |
113 | | -- name: import grafana dashboards through API |
| 74 | +- name: Import grafana dashboards through API |
114 | 75 | uri: |
115 | 76 | url: "{{ grafana_api_url }}/api/dashboards/db" |
116 | 77 | user: "{{ grafana_security.admin_user }}" |
117 | 78 | password: "{{ grafana_security.admin_password }}" |
118 | 79 | force_basic_auth: true |
119 | 80 | method: POST |
120 | 81 | body_format: json |
121 | | - body: '{ "dashboard": {{ lookup("file", item) }}, "overwrite": true, "message": "Updated by ansible" }' |
| 82 | + body: > |
| 83 | + { |
| 84 | + "dashboard": {{ lookup("file", item) }}, |
| 85 | + "overwrite": true, |
| 86 | + "message": "Updated by ansible" |
| 87 | + } |
122 | 88 | no_log: true |
123 | 89 | with_fileglob: |
124 | | - - "/tmp/dashboards/*" |
| 90 | + - "{{ _tmp_dashboards.path }}/*" |
| 91 | + - "{{ grafana_dashboards_dir }}/*.json" |
125 | 92 | when: not grafana_use_provisioning |
126 | 93 |
|
127 | 94 | # TODO: uncomment this when ansible 2.7 will be min supported version |
|
138 | 105 | # with_fileglob: |
139 | 106 | # - "/tmp/dashboards/*" |
140 | 107 |
|
141 | | -- name: Create/Update dashboards file (provisioning) |
142 | | - become: true |
143 | | - copy: |
144 | | - dest: "/etc/grafana/provisioning/dashboards/ansible.yml" |
145 | | - content: | |
146 | | - apiVersion: 1 |
147 | | - providers: |
148 | | - - name: 'default' |
149 | | - orgId: 1 |
150 | | - folder: '' |
151 | | - type: file |
152 | | - options: |
153 | | - path: /var/lib/grafana/dashboards |
154 | | - backup: false |
155 | | - owner: root |
156 | | - group: grafana |
157 | | - mode: 0640 |
158 | | - notify: restart grafana |
159 | | - when: grafana_use_provisioning |
| 108 | +- when: grafana_use_provisioning |
| 109 | + block: |
| 110 | + - name: Create/Update dashboards file (provisioning) |
| 111 | + become: true |
| 112 | + copy: |
| 113 | + dest: "/etc/grafana/provisioning/dashboards/ansible.yml" |
| 114 | + content: | |
| 115 | + apiVersion: 1 |
| 116 | + providers: |
| 117 | + - name: 'default' |
| 118 | + orgId: 1 |
| 119 | + folder: '' |
| 120 | + type: file |
| 121 | + options: |
| 122 | + path: /var/lib/grafana/dashboards |
| 123 | + backup: false |
| 124 | + owner: root |
| 125 | + group: grafana |
| 126 | + mode: 0640 |
| 127 | + notify: restart grafana |
| 128 | + |
| 129 | + - name: Register previously copied dashboards |
| 130 | + find: |
| 131 | + paths: "/var/lib/grafana/dashboards" |
| 132 | + hidden: true |
| 133 | + patterns: |
| 134 | + - "*.json" |
| 135 | + register: _dashboards_present |
| 136 | + when: grafana_provisioning_synced |
| 137 | + |
| 138 | + - name: Import grafana dashboards |
| 139 | + become: true |
| 140 | + copy: |
| 141 | + src: "{{ item }}" |
| 142 | + dest: "/var/lib/grafana/dashboards/{{ item | basename }}" |
| 143 | + with_fileglob: |
| 144 | + - "{{ _tmp_dashboards.path }}/*" |
| 145 | + - "{{ grafana_dashboards_dir }}/*.json" |
| 146 | + register: _dashboards_copied |
| 147 | + notify: "provisioned dashboards changed" |
| 148 | + |
| 149 | + - name: Get dashboard lists |
| 150 | + set_fact: |
| 151 | + _dashboards_present_list: "{{ _dashboards_present | json_query('files[*].path') | default([]) }}" |
| 152 | + _dashboards_copied_list: "{{ _dashboards_copied | json_query('results[*].dest') | default([]) }}" |
| 153 | + when: grafana_provisioning_synced |
160 | 154 |
|
161 | | -- name: Import grafana dashboards through provisioning |
162 | | - become: true |
163 | | - synchronize: |
164 | | - src: "/tmp/dashboards/" |
165 | | - dest: "/var/lib/grafana/dashboards" |
166 | | - archive: false |
167 | | - checksum: true |
168 | | - recursive: true |
169 | | - delete: "{{ grafana_provisioning_synced }}" |
170 | | - rsync_opts: |
171 | | - - "--no-motd" |
172 | | - when: grafana_use_provisioning |
173 | | - notify: "provisioned dashboards changed" |
| 155 | + - name: Remove dashbards not present on deployer machine (synchronize) |
| 156 | + become: true |
| 157 | + file: |
| 158 | + path: "{{ item }}" |
| 159 | + state: absent |
| 160 | + with_items: "{{ _dashboards_present_list | difference( _dashboards_copied_list ) }}" |
| 161 | + when: grafana_provisioning_synced |
0 commit comments