Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dashboard): manage dashboards by org_name #331

Merged
merged 18 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions changelogs/fragments/331-dashboard-by-org-name.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---

minor_changes:
- Add parameter `org_name` to `grafana_dashboard`

trivial:
- Add tests for new `grafana_dashboard`-parameter `org_name`
- Refactor tests for `grafana_dashboard`
35 changes: 29 additions & 6 deletions plugins/modules/grafana_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,17 @@
options:
org_id:
description:
- The Grafana Organisation ID where the dashboard will be imported / exported.
- Not used when I(grafana_api_key) is set, because the grafana_api_key only belongs to one organisation..
- The Grafana organization ID where the dashboard will be imported / exported / deleted.
- Not used when I(grafana_api_key) is set, because the grafana_api_key only belongs to one organization.
- Mutually exclusive with `org_name`.
default: 1
type: int
org_name:
description:
- The Grafana organization name where the dashboard will be imported / exported / deleted.
- Not used when I(grafana_api_key) is set, because the grafana_api_key only belongs to one organization.
- Mutually exclusive with `org_id`.
type: str
folder:
description:
- The Grafana folder where this dashboard will be imported to.
Expand Down Expand Up @@ -157,7 +164,19 @@
pass


def grafana_switch_organisation(module, grafana_url, org_id, headers):
def grafana_organization_id_by_name(module, grafana_url, org_name, headers):
r, info = fetch_url(module, '%s/api/user/orgs' % grafana_url, headers=headers, method='GET')
if info['status'] != 200:
raise GrafanaAPIException("Unable to retrieve users organizations: %s" % info)

Check warning on line 170 in plugins/modules/grafana_dashboard.py

View check run for this annotation

Codecov / codecov/patch

plugins/modules/grafana_dashboard.py#L170

Added line #L170 was not covered by tests
organizations = json.loads(to_text(r.read()))
for org in organizations:
if org['name'] == org_name:
return org['orgId']

raise GrafanaAPIException("Current user isn't member of organization: %s" % org_name)

Check warning on line 176 in plugins/modules/grafana_dashboard.py

View check run for this annotation

Codecov / codecov/patch

plugins/modules/grafana_dashboard.py#L176

Added line #L176 was not covered by tests


def grafana_switch_organization(module, grafana_url, org_id, headers):
r, info = fetch_url(module, '%s/api/user/using/%s' % (grafana_url, org_id), headers=headers, method='POST')
if info['status'] != 200:
raise GrafanaAPIException('Unable to switch to organization %s : %s' % (org_id, info))
Expand All @@ -169,7 +188,10 @@
headers['Authorization'] = "Bearer %s" % data['grafana_api_key']
else:
module.params['force_basic_auth'] = True
grafana_switch_organisation(module, data['url'], data['org_id'], headers)
if module.params['org_name']:
org_name = module.params['org_name']
data['org_id'] = grafana_organization_id_by_name(module, data['url'], org_name, headers)
grafana_switch_organization(module, data['url'], data['org_id'], headers)

return headers

Expand All @@ -186,7 +208,7 @@
except Exception as e:
raise GrafanaAPIException(e)
else:
raise GrafanaAPIException('Unable to get grafana version : %s' % info)
raise GrafanaAPIException('Unable to get grafana version: %s' % info)

Check warning on line 211 in plugins/modules/grafana_dashboard.py

View check run for this annotation

Codecov / codecov/patch

plugins/modules/grafana_dashboard.py#L211

Added line #L211 was not covered by tests

return int(grafana_version)

Expand Down Expand Up @@ -490,6 +512,7 @@
argument_spec.update(
state=dict(choices=['present', 'absent', 'export'], default='present'),
org_id=dict(default=1, type='int'),
org_name=dict(type='str'),
folder=dict(type='str', default='General'),
uid=dict(type='str'),
slug=dict(type='str'),
Expand All @@ -508,7 +531,7 @@
['state', 'export', ['path']],
],
required_together=[['url_username', 'url_password', 'org_id']],
mutually_exclusive=[['url_username', 'grafana_api_key'], ['uid', 'slug'], ['path', 'dashboard_id']],
mutually_exclusive=[['url_username', 'grafana_api_key'], ['uid', 'slug'], ['path', 'dashboard_id'], ['org_id', 'org_name']],
)

module.params["url"] = clean_url(module.params["url"])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
---

grafana_url: "http://grafana:3000/"
grafana_username: "admin"
grafana_password: "admin"

...
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
- module_defaults:
community.grafana.grafana_dashboard:
org_name: Main Org.
block:
- name: Check import grafana dashboard from file
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: present
commit_message: Updated by ansible
path: /tmp/dashboard.json
overwrite: true
register: result
- ansible.builtin.assert:
that:
- "result.failed == false"
- "result.changed == true"
- "result.msg == 'Dashboard test created'"

- name: Check import grafana dashboard from file idempotency
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: present
commit_message: Updated by ansible
path: /tmp/dashboard.json
overwrite: true
register: result
- ansible.builtin.assert:
that:
- "result.failed == false"
- "result.changed == false"
- "result.msg == 'Dashboard test unchanged.'"

- ansible.builtin.include_tasks: delete-dashboard.yml
Original file line number Diff line number Diff line change
@@ -1,32 +1,26 @@
---
- set_fact:
dashboard_uid: "{{ result.uid }}"

- name: Check export grafana dashboard to file
grafana_dashboard:
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: export
path: /tmp/dashboard.json
path: /tmp/dashboard_export.json
overwrite: true
uid: "{{ dashboard_uid }}"
uid: "{{ result.uid }}"
register: result

- debug:
var: result

- assert:
- ansible.builtin.assert:
that:
- "result.failed == false"
- "result.changed == true"
- "result.msg == 'Dashboard {{ dashboard_uid }} exported to /tmp/dashboard.json'"
- "result.msg == 'Dashboard ' ~ result.uid ~ ' exported to /tmp/dashboard_export.json'"

- name: Load /tmp/dashboard.json or fail if missing
set_fact:
exported_dashboard_lines: "{{ lookup('file', '/tmp/dashboard.json').splitlines() }}"
- name: Load /tmp/dashboard_export.json or fail if missing
ansible.builtin.set_fact:
exported_dashboard_lines: "{{ lookup('file', '/tmp/dashboard_export.json').splitlines() }}"

- name: Assert that exported dashboard contains formatted JSON
assert:
ansible.builtin.assert:
that:
- "exported_dashboard_lines | length >= 2"
- "exported_dashboard_lines[0] == '{'"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,18 @@
---
- name: copy dashboard file
copy:
src: "files/dashboard.json"
dest: "/tmp/dashboard.json"

- block:
- name: Check import grafana dashboard from file to unknown folder fails
grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: present
commit_message: Updated by ansible
path: /tmp/dashboard.json
overwrite: true
folder: inexistent
register: result
ignore_errors: true

- debug:
var: result

- set_fact:
# XXX: Too many quotes of different types to do inline.
# I did not manage to find a good way of having it inline.
expected_error: "error : Dashboard folder 'inexistent' does not exist."

- assert:
- name: Check import grafana dashboard from file to unknown folder fails
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: present
commit_message: Updated by ansible
path: /tmp/dashboard.json
overwrite: true
folder: inexistent
register: result
ignore_errors: true
- ansible.builtin.assert:
that:
- "result.changed == false"
- "result.failed == true"
- "result.msg == expected_error"
- "result.changed == false"
- "result.msg == 'error : Dashboard folder \\'inexistent\\' does not exist.'"
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
---
- name: copy dashboard file
copy:
- name: Copy dashboard file
ansible.builtin.copy:
src: "files/dashboard.json"
dest: "/tmp/dashboard.json"


- name: Check import grafana dashboard from file
grafana_dashboard:
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
Expand All @@ -15,17 +14,14 @@
path: /tmp/dashboard.json
overwrite: true
register: result

- debug:
var: result

- assert:
- ansible.builtin.assert:
that:
- "result.failed == false"
- "result.changed == true"
- "result.msg == 'Dashboard test created'"

- name: Check import grafana dashboard from file idempotency
grafana_dashboard:
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
Expand All @@ -34,11 +30,12 @@
path: /tmp/dashboard.json
overwrite: true
register: result

- debug:
var: result

- assert:
- ansible.builtin.assert:
that:
- "result.failed == false"
- "result.changed == false"
- "result.msg == 'Dashboard test unchanged.'"

- ansible.builtin.include_tasks: dashboard-export.yml

- ansible.builtin.include_tasks: delete-dashboard.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
- name: Check import grafana dashboard from id
grafana_dashboard:
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
Expand All @@ -10,17 +10,14 @@
dashboard_revision: "1"
overwrite: true
register: result

- debug:
var: result

- assert:
that:
- "result.failed == false"
- "result.changed == true"
- "result.msg == 'Dashboard Zabbix Host Status created'"

- name: Check import grafana dashboard from id idempotency
grafana_dashboard:
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
Expand All @@ -30,11 +27,10 @@
dashboard_revision: "1"
overwrite: true
register: result

- debug:
var: result

- assert:
- ansible.builtin.assert:
that:
- "result.failed == false"
- "result.changed == false"
- "result.msg == 'Dashboard Zabbix Host Status unchanged.'"

- ansible.builtin.include_tasks: delete-dashboard.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---

- name: Check import grafana dashboard from url
grafana_dashboard:
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
Expand All @@ -10,17 +9,14 @@
dashboard_url: https://grafana.com/api/dashboards/6098/revisions/1/download
overwrite: true
register: result

- debug:
var: result

- assert:
that:
- "result.failed == false"
- "result.changed == true"
- "result.msg == 'Dashboard Zabbix Host Status created'"

- name: Check import grafana dashboard from url idempotency
grafana_dashboard:
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
Expand All @@ -29,11 +25,10 @@
dashboard_url: https://grafana.com/api/dashboards/6098/revisions/1/download
overwrite: true
register: result

- debug:
var: result

- assert:
- ansible.builtin.assert:
that:
- "result.failed == false"
- "result.changed == false"
- "result.msg == 'Dashboard Zabbix Host Status unchanged.'"

- ansible.builtin.include_tasks: delete-dashboard.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
- name: Check delete dashboard is working
grafana_dashboard:
---
- name: Delete dashboard
community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
uid: "{{ result.uid }}"
register: result

- debug:
var: result

- assert:
- ansible.builtin.assert:
that:
- "result.failed == false"
- "result.changed == true"
- "result.msg == 'Dashboard {{ result.uid }} deleted'"
- "result.msg == 'Dashboard ' ~ result.uid ~ ' deleted'"
Loading
Loading