From 390a85034bbe7a8ff7c2a5920d92f94b49bf3d67 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Tue, 17 Oct 2023 15:44:32 +0200 Subject: [PATCH 01/18] feat: manage organization users --- tasks/main.yml | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tasks/main.yml b/tasks/main.yml index 937ebd3..ad2e610 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -68,6 +68,57 @@ loop_var: user tags: user +# community.grafana 1.6.0 release required +# - name: Manage organization user +# community.grafana.grafana_organization_user: +# url: "{{ grafana_url }}" +# url_username: "{{ grafana_username }}" +# url_password: "{{ grafana_password }}" +# login: "{{ organization_user.login }}" +# role: "{{ organization_user.role | default(omit) }}" +# state: "{{ organization_user.state | default(omit) }}" +# org_id: "{{ organization_user.org_id | default(omit) }}" +# loop: "{{ grafana_organization_users | selectattr('org_name', 'undefined') | list }}" +# loop_control: {loop_var: organization_user} +# tags: organization_user + +- name: Get organizations + ansible.builtin.uri: + url: "{{ grafana_url }}/api/orgs/name/{{ organization_user.org_name | urlencode }}" + url_username: "{{ grafana_username }}" + url_password: "{{ grafana_password }}" + force_basic_auth: true + return_content: true + loop: "{{ grafana_organization_users | selectattr('org_name', 'defined') | list | unique }}" + loop_control: {loop_var: organization_user} + tags: organization_user + register: _grafana_organizations + +- name: Get users + ansible.builtin.uri: + url: "{{ grafana_url }}/api/users/lookup?loginOrEmail={{ user.login | default(user.email) | urlencode }}" + url_username: "{{ grafana_username }}" + url_password: "{{ grafana_password }}" + force_basic_auth: true + return_content: true + loop: "{{ grafana_organization_users | selectattr('state', 'eq', 'absent') | list }}" + loop_control: {loop_var: user} + when: "{{ grafana_organization_users | selectattr('state', 'defined') }}" + tags: organization_user + register: _grafana_users + +- name: Manage organization user + ansible.builtin.uri: + url: "{{ grafana_url }}/api/orgs/{{ _org_id }}/users{{ '/' ~ _user_id if organization_user.state | default('') == 'absent' else '' }}" + url_username: "{{ grafana_username }}" + url_password: "{{ grafana_password }}" + force_basic_auth: true + return_content: true + body: + loginOrEmail: "{{ organization_user.login | default(organization_user.email) }}" + role: "{{ organization_user.role | default(omit) }}" + body_format: json + - name: Manage dashboard community.grafana.grafana_dashboard: grafana_url: "{{ grafana_url }}" From 9f36358712ebacd049ba25afd528f5fc7d731aba Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Tue, 17 Oct 2023 15:48:11 +0200 Subject: [PATCH 02/18] style: comments --- tasks/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/main.yml b/tasks/main.yml index ad2e610..d6fe628 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -68,7 +68,7 @@ loop_var: user tags: user -# community.grafana 1.6.0 release required +### community.grafana 1.6.0 release required # - name: Manage organization user # community.grafana.grafana_organization_user: # url: "{{ grafana_url }}" From 8bee405c5a5d02b74f55875dd605ca0b09d3172a Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:36:10 +0200 Subject: [PATCH 03/18] refactor: split task files for orga user mgmt --- tasks/main.yml | 52 ++--------------------------- tasks/organization_users.yml | 63 ++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 50 deletions(-) create mode 100644 tasks/organization_users.yml diff --git a/tasks/main.yml b/tasks/main.yml index d6fe628..94bedec 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -68,56 +68,8 @@ loop_var: user tags: user -### community.grafana 1.6.0 release required -# - name: Manage organization user -# community.grafana.grafana_organization_user: -# url: "{{ grafana_url }}" -# url_username: "{{ grafana_username }}" -# url_password: "{{ grafana_password }}" -# login: "{{ organization_user.login }}" -# role: "{{ organization_user.role | default(omit) }}" -# state: "{{ organization_user.state | default(omit) }}" -# org_id: "{{ organization_user.org_id | default(omit) }}" -# loop: "{{ grafana_organization_users | selectattr('org_name', 'undefined') | list }}" -# loop_control: {loop_var: organization_user} -# tags: organization_user - -- name: Get organizations - ansible.builtin.uri: - url: "{{ grafana_url }}/api/orgs/name/{{ organization_user.org_name | urlencode }}" - url_username: "{{ grafana_username }}" - url_password: "{{ grafana_password }}" - force_basic_auth: true - return_content: true - loop: "{{ grafana_organization_users | selectattr('org_name', 'defined') | list | unique }}" - loop_control: {loop_var: organization_user} - tags: organization_user - register: _grafana_organizations - -- name: Get users - ansible.builtin.uri: - url: "{{ grafana_url }}/api/users/lookup?loginOrEmail={{ user.login | default(user.email) | urlencode }}" - url_username: "{{ grafana_username }}" - url_password: "{{ grafana_password }}" - force_basic_auth: true - return_content: true - loop: "{{ grafana_organization_users | selectattr('state', 'eq', 'absent') | list }}" - loop_control: {loop_var: user} - when: "{{ grafana_organization_users | selectattr('state', 'defined') }}" - tags: organization_user - register: _grafana_users - -- name: Manage organization user - ansible.builtin.uri: - url: "{{ grafana_url }}/api/orgs/{{ _org_id }}/users{{ '/' ~ _user_id if organization_user.state | default('') == 'absent' else '' }}" - url_username: "{{ grafana_username }}" - url_password: "{{ grafana_password }}" - force_basic_auth: true - return_content: true - body: - loginOrEmail: "{{ organization_user.login | default(organization_user.email) }}" - role: "{{ organization_user.role | default(omit) }}" - body_format: json +- name: Organization users + ansible.builtin.include_tasks: organization_users.yml - name: Manage dashboard community.grafana.grafana_dashboard: diff --git a/tasks/organization_users.yml b/tasks/organization_users.yml new file mode 100644 index 0000000..e2a5d50 --- /dev/null +++ b/tasks/organization_users.yml @@ -0,0 +1,63 @@ +--- +# community.grafana 1.6.0 release required +- name: Manage organization user + community.grafana.grafana_organization_user: + url: "{{ grafana_url }}" + url_username: "{{ grafana_username }}" + url_password: "{{ grafana_password }}" + login: "{{ organization_user.login }}" + role: "{{ organization_user.role | default(omit) }}" + state: "{{ organization_user.state | default(omit) }}" + org_id: "{{ organization_user.org_id | default(omit) }}" + loop: "{{ grafana_organization_users | selectattr('org_name', 'undefined') | list }}" + loop_control: {loop_var: organization_user} + tags: organization_user + +- name: Grafana organization API tasks + tags: organization_user + module_defaults: + ansible.builtin.uri: + url_username: "{{ grafana_username }}" + url_password: "{{ grafana_password }}" + force_basic_auth: true + return_content: true + block: + - name: Get organizations + ansible.builtin.uri: + url: "{{ grafana_url }}/api/orgs/name/{{ organization_user.org_name | urlencode }}" + loop: "{{ grafana_organization_users | selectattr('org_name', 'defined') | list | unique }}" + loop_control: {loop_var: organization_user} + register: _grafana_organizations + + - name: Get users + ansible.builtin.uri: + url: "{{ grafana_url }}/api/users/lookup?loginOrEmail={{ user.login | default(user.email) | urlencode }}" + loop: "{{ grafana_organization_users | selectattr('state', 'eq', 'absent') | list }}" + loop_control: {loop_var: user} + when: "{{ grafana_organization_users | selectattr('state', 'defined') }}" + register: _grafana_users + + - name: Manage organization user + ansible.builtin.uri: + url: "{{ grafana_url }}/api/orgs/{{ _org_id }}/users{{ '/' ~ _user_id if organization_user.state | default('') == 'absent' else '' }}" + body: + loginOrEmail: "{{ organization_user.login | default(organization_user.email) }}" + role: "{{ organization_user.role | default(omit) }}" + body_format: json + method: "{{ 'DELETE' if organization_user.state | default('') == 'absent' else 'POST' }}" + loop: "{{ grafana_organization_users | selectattr('org_name', 'defined') }}" + loop_control: {loop_var: organization_user} + vars: + _org_id: "{{ _grafana_organizations.results | + map(attribute='json') | + selectattr('name', 'eq', organization_user.org_name) | + map(attribute='id') | + first }}" + _user_id: "{{ _grafana_users.results | + map(attribute='json') | + selectattr('login', 'eq', organization_user.login) | + map(attribute='id') | + first }}" + register: _grafana_organization_user + changed_when: _grafana_organization_user.json.message in ["User added to organization", "User removed from organization"] + failed_when: _grafana_organization_user.json.message != "User is already member of this organization" From 41e687d8ebe593c810a41032471e6ac5d5c17af1 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:42:25 +0200 Subject: [PATCH 04/18] docs: orga users --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index b38275a..d2f212f 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,13 @@ community.grafana | dashboard_id | no | | dashboard_revision | no | | commit_message | no | + ## Example Playbook From 85a74adbe5d4a2abec69678abd165b0803939112 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:15:47 +0200 Subject: [PATCH 05/18] refactor: simplify vars and reorganize tags --- tasks/main.yml | 2 ++ tasks/organization_users.yml | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tasks/main.yml b/tasks/main.yml index 94bedec..378df39 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -70,6 +70,8 @@ - name: Organization users ansible.builtin.include_tasks: organization_users.yml + apply: {tags: organization_user} + tags: always - name: Manage dashboard community.grafana.grafana_dashboard: diff --git a/tasks/organization_users.yml b/tasks/organization_users.yml index e2a5d50..fb55fba 100644 --- a/tasks/organization_users.yml +++ b/tasks/organization_users.yml @@ -11,16 +11,15 @@ org_id: "{{ organization_user.org_id | default(omit) }}" loop: "{{ grafana_organization_users | selectattr('org_name', 'undefined') | list }}" loop_control: {loop_var: organization_user} - tags: organization_user - name: Grafana organization API tasks - tags: organization_user module_defaults: ansible.builtin.uri: url_username: "{{ grafana_username }}" url_password: "{{ grafana_password }}" force_basic_auth: true return_content: true + when: "{{ grafana_organization_users | selectattr('org_name', 'defined') | list > 0 }}" block: - name: Get organizations ansible.builtin.uri: @@ -31,7 +30,7 @@ - name: Get users ansible.builtin.uri: - url: "{{ grafana_url }}/api/users/lookup?loginOrEmail={{ user.login | default(user.email) | urlencode }}" + url: "{{ grafana_url }}/api/users/lookup?loginOrEmail={{ user.login | urlencode }}" loop: "{{ grafana_organization_users | selectattr('state', 'eq', 'absent') | list }}" loop_control: {loop_var: user} when: "{{ grafana_organization_users | selectattr('state', 'defined') }}" @@ -39,15 +38,16 @@ - name: Manage organization user ansible.builtin.uri: - url: "{{ grafana_url }}/api/orgs/{{ _org_id }}/users{{ '/' ~ _user_id if organization_user.state | default('') == 'absent' else '' }}" + url: "{{ grafana_url }}/api/orgs/{{ _org_id }}/users{{ '/' ~ _user_id if _organization_user_state == 'absent' else '' }}" body: - loginOrEmail: "{{ organization_user.login | default(organization_user.email) }}" + loginOrEmail: "{{ organization_user.login }}" role: "{{ organization_user.role | default(omit) }}" body_format: json - method: "{{ 'DELETE' if organization_user.state | default('') == 'absent' else 'POST' }}" + method: "{{ 'DELETE' if _organization_user_state == 'absent' else 'POST' }}" loop: "{{ grafana_organization_users | selectattr('org_name', 'defined') }}" loop_control: {loop_var: organization_user} vars: + _organization_user_state: "{{ organization_user.state | default('') }}" _org_id: "{{ _grafana_organizations.results | map(attribute='json') | selectattr('name', 'eq', organization_user.org_name) | From f03c6dc7dfb9f5c38132d8e5b339a5fb65d6c110 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:20:03 +0200 Subject: [PATCH 06/18] fix: include task apply tags and file --- tasks/main.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tasks/main.yml b/tasks/main.yml index 378df39..b9983c5 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -69,8 +69,9 @@ tags: user - name: Organization users - ansible.builtin.include_tasks: organization_users.yml - apply: {tags: organization_user} + ansible.builtin.include_tasks: + file: organization_users.yml + apply: {tags: organization_user} tags: always - name: Manage dashboard From 3e5d5f612672fded6a7f0132301cab421bc27403 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:21:39 +0200 Subject: [PATCH 07/18] fix: list length conditional --- tasks/organization_users.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/organization_users.yml b/tasks/organization_users.yml index fb55fba..72b996d 100644 --- a/tasks/organization_users.yml +++ b/tasks/organization_users.yml @@ -19,7 +19,7 @@ url_password: "{{ grafana_password }}" force_basic_auth: true return_content: true - when: "{{ grafana_organization_users | selectattr('org_name', 'defined') | list > 0 }}" + when: grafana_organization_users | selectattr('org_name', 'defined') | list | length > 0 block: - name: Get organizations ansible.builtin.uri: @@ -33,7 +33,7 @@ url: "{{ grafana_url }}/api/users/lookup?loginOrEmail={{ user.login | urlencode }}" loop: "{{ grafana_organization_users | selectattr('state', 'eq', 'absent') | list }}" loop_control: {loop_var: user} - when: "{{ grafana_organization_users | selectattr('state', 'defined') }}" + when: grafana_organization_users | selectattr('state', 'defined') register: _grafana_users - name: Manage organization user From 10df45088e880eec25e755cad2dca9a230e55119 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Wed, 18 Oct 2023 12:56:27 +0200 Subject: [PATCH 08/18] chore: org users default var --- defaults/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/defaults/main.yml b/defaults/main.yml index d3e5e96..3b4eb4f 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,4 +1,5 @@ --- +grafana_organization_users: [] grafana_users: [] grafana_teams: [] grafana_datasources: [] From a73376cb0f1615f12d4ac7cce192a0bcfed696c2 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Wed, 18 Oct 2023 12:57:48 +0200 Subject: [PATCH 09/18] fix: get orgs loop, get users loop, error handling org user mgmt --- tasks/organization_users.yml | 43 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/tasks/organization_users.yml b/tasks/organization_users.yml index 72b996d..54ec687 100644 --- a/tasks/organization_users.yml +++ b/tasks/organization_users.yml @@ -1,16 +1,16 @@ --- -# community.grafana 1.6.0 release required -- name: Manage organization user - community.grafana.grafana_organization_user: - url: "{{ grafana_url }}" - url_username: "{{ grafana_username }}" - url_password: "{{ grafana_password }}" - login: "{{ organization_user.login }}" - role: "{{ organization_user.role | default(omit) }}" - state: "{{ organization_user.state | default(omit) }}" - org_id: "{{ organization_user.org_id | default(omit) }}" - loop: "{{ grafana_organization_users | selectattr('org_name', 'undefined') | list }}" - loop_control: {loop_var: organization_user} +# requires community.grafana >= 1.6.0 +# - name: Manage organization users by org_id +# community.grafana.grafana_organization_user: +# url: "{{ grafana_url }}" +# url_username: "{{ grafana_username }}" +# url_password: "{{ grafana_password }}" +# login: "{{ organization_user.login }}" +# role: "{{ organization_user.role | default(omit) }}" +# state: "{{ organization_user.state | default(omit) }}" +# org_id: "{{ organization_user.org_id | default(omit) }}" +# loop: "{{ grafana_organization_users | selectattr('org_id', 'defined') | list }}" +# loop_control: {loop_var: organization_user} - name: Grafana organization API tasks module_defaults: @@ -23,31 +23,31 @@ block: - name: Get organizations ansible.builtin.uri: - url: "{{ grafana_url }}/api/orgs/name/{{ organization_user.org_name | urlencode }}" - loop: "{{ grafana_organization_users | selectattr('org_name', 'defined') | list | unique }}" - loop_control: {loop_var: organization_user} + url: "{{ grafana_url }}/api/orgs/name/{{ organization_names | urlencode }}" + loop: "{{ grafana_organization_users | map(attribute='org_name') | unique | list }}" + loop_control: {loop_var: organization_names} register: _grafana_organizations - name: Get users ansible.builtin.uri: url: "{{ grafana_url }}/api/users/lookup?loginOrEmail={{ user.login | urlencode }}" - loop: "{{ grafana_organization_users | selectattr('state', 'eq', 'absent') | list }}" + loop: "{{ grafana_organization_users | selectattr('state', 'defined') | selectattr('state', 'eq', 'absent') | list }}" loop_control: {loop_var: user} - when: grafana_organization_users | selectattr('state', 'defined') register: _grafana_users - - name: Manage organization user + - name: Manage organization users by org_name ansible.builtin.uri: - url: "{{ grafana_url }}/api/orgs/{{ _org_id }}/users{{ '/' ~ _user_id if _organization_user_state == 'absent' else '' }}" + url: "{{ grafana_url }}/api/orgs/{{ _org_id }}/users{{ '/' ~ _user_id if _org_user_state == 'absent' else '' }}" body: loginOrEmail: "{{ organization_user.login }}" role: "{{ organization_user.role | default(omit) }}" body_format: json - method: "{{ 'DELETE' if _organization_user_state == 'absent' else 'POST' }}" + method: "{{ 'DELETE' if _org_user_state == 'absent' else 'POST' }}" + status_code: ["200", "409"] loop: "{{ grafana_organization_users | selectattr('org_name', 'defined') }}" loop_control: {loop_var: organization_user} vars: - _organization_user_state: "{{ organization_user.state | default('') }}" + _org_user_state: "{{ organization_user.state | default('') }}" _org_id: "{{ _grafana_organizations.results | map(attribute='json') | selectattr('name', 'eq', organization_user.org_name) | @@ -60,4 +60,3 @@ first }}" register: _grafana_organization_user changed_when: _grafana_organization_user.json.message in ["User added to organization", "User removed from organization"] - failed_when: _grafana_organization_user.json.message != "User is already member of this organization" From 66371b2f21da09a682c668ef0c3336abb77e98cd Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Wed, 18 Oct 2023 12:59:21 +0200 Subject: [PATCH 10/18] fix: include tasks tag handling and conditonal --- tasks/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tasks/main.yml b/tasks/main.yml index b9983c5..440a6d4 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -72,7 +72,8 @@ ansible.builtin.include_tasks: file: organization_users.yml apply: {tags: organization_user} - tags: always + when: grafana_organization_users | length > 0 + tags: organization_user - name: Manage dashboard community.grafana.grafana_dashboard: From f6c7eff74b9a87faaa331e1ada3692fe9eeb9eef Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Wed, 18 Oct 2023 13:04:02 +0200 Subject: [PATCH 11/18] docs: org user mgmt params and notice --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d2f212f..b86b43f 100644 --- a/README.md +++ b/README.md @@ -62,13 +62,14 @@ community.grafana | dashboard_id | no | | dashboard_revision | no | | commit_message | no | - +--> ## Example Playbook From 37f8440ecaec2dc7cde2d2765b9de35de541852c Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:05:24 +0100 Subject: [PATCH 12/18] chore(deps): increase community.grafana version --- requirements.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.yml b/requirements.yml index 364da58..49d4768 100644 --- a/requirements.yml +++ b/requirements.yml @@ -1,2 +1,2 @@ --- -collections: [{name: community.grafana, version: 1.5.4}] +collections: [{name: community.grafana, version: 1.6.0}] From 8ae4004cfe96918a1d5499d58bb53e5391040fc9 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:10:17 +0100 Subject: [PATCH 13/18] docs: fix table --- README.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index fe9ab1f..90df60a 100644 --- a/README.md +++ b/README.md @@ -18,25 +18,24 @@ Configure Grafana organizations, dashboards, folders, datasources, teams and use | grafana_url | yes | | grafana_username | yes | | grafana_password | yes | - -| [**grafana_users**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_user_module.html) +| [**grafana_users**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_user_module.html) | | name | yes | | email | no | | login | yes | | password | no | | is_admin | no | | state | no | -| [**grafana_organizations**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_organization_module.html) +| [**grafana_organizations**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_organization_module.html) | | name | yes | | state | no | -| [**grafana_teams**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_team_module.html) +| [**grafana_teams**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_team_module.html) | | name | yes | | email | no | | members | no | | state | no | | enforce_members | no | | skip_version_check | no | -| [**grafana_datasources**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_datasource_module.html) +| [**grafana_datasources**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_datasource_module.html) | | tls_skip_verify | no | | org_id | no | | name | yes | @@ -50,11 +49,11 @@ Configure Grafana organizations, dashboards, folders, datasources, teams and use | password | no | | additional_json_data | no | | additional_secure_json_data | no | -| [**grafana_folders**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_folder_module.html) +| [**grafana_folders**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_folder_module.html) | | name | yes | | state | no | | skip_version_check | no | -| [**grafana_dashboards**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_dashboard_module.html) +| [**grafana_dashboards**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_dashboard_module.html) | | org_id | no | | folder | no | | state | no | @@ -65,14 +64,12 @@ Configure Grafana organizations, dashboards, folders, datasources, teams and use | dashboard_id | no | | dashboard_revision | no | | commit_message | no | -| [**grafana_organization_users**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_organization_user_module.html) +| [**grafana_organization_users**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_organization_user_module.html) | | login | yes | | role | no | | state | no | | org_name | no | - ## Example Playbook From 420527bd6be7d137a06efe0fcaa26f4dfabacea5 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:10:39 +0100 Subject: [PATCH 14/18] feat: enable org users with org_id --- tasks/organization_users.yml | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tasks/organization_users.yml b/tasks/organization_users.yml index 54ec687..9b28e84 100644 --- a/tasks/organization_users.yml +++ b/tasks/organization_users.yml @@ -1,16 +1,15 @@ --- -# requires community.grafana >= 1.6.0 -# - name: Manage organization users by org_id -# community.grafana.grafana_organization_user: -# url: "{{ grafana_url }}" -# url_username: "{{ grafana_username }}" -# url_password: "{{ grafana_password }}" -# login: "{{ organization_user.login }}" -# role: "{{ organization_user.role | default(omit) }}" -# state: "{{ organization_user.state | default(omit) }}" -# org_id: "{{ organization_user.org_id | default(omit) }}" -# loop: "{{ grafana_organization_users | selectattr('org_id', 'defined') | list }}" -# loop_control: {loop_var: organization_user} +- name: Manage organization users by org_id + community.grafana.grafana_organization_user: + url: "{{ grafana_url }}" + url_username: "{{ grafana_username }}" + url_password: "{{ grafana_password }}" + login: "{{ organization_user.login }}" + role: "{{ organization_user.role | default(omit) }}" + state: "{{ organization_user.state | default(omit) }}" + org_id: "{{ organization_user.org_id | default(omit) }}" + loop: "{{ grafana_organization_users | selectattr('org_id', 'defined') | list }}" + loop_control: {loop_var: organization_user} - name: Grafana organization API tasks module_defaults: From b2ef53c7facb553bf9463430580f538923a84a49 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:34:32 +0100 Subject: [PATCH 15/18] docs: org_name or _id --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 90df60a..fb46493 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,7 @@ Configure Grafana organizations, dashboards, folders, datasources, teams and use | login | yes | | role | no | | state | no | -| org_name | no | -| org_id | no | +| org_id / org_name | no | ## Example Playbook From acd3e96ca281deb47bfdefd231e8df23be06f397 Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Fri, 3 Nov 2023 17:18:27 +0100 Subject: [PATCH 16/18] refactor: removed org_name URI user mgmt in favour of community.grafana module enhancement --- tasks/main.yml | 17 +++++++--- tasks/organization_users.yml | 61 ------------------------------------ 2 files changed, 12 insertions(+), 66 deletions(-) delete mode 100644 tasks/organization_users.yml diff --git a/tasks/main.yml b/tasks/main.yml index 086d28a..8c59b9e 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -75,11 +75,18 @@ loop_control: {loop_var: user} tags: user -- name: Organization users - ansible.builtin.include_tasks: - file: organization_users.yml - apply: {tags: organization_user} - when: grafana_organization_users | length > 0 +- name: Manage organization users + community.grafana.grafana_organization_user: + url: "{{ grafana_url }}" + url_username: "{{ grafana_username }}" + url_password: "{{ grafana_password }}" + login: "{{ organization_user.login }}" + role: "{{ organization_user.role | default(omit) }}" + state: "{{ organization_user.state | default(omit) }}" + org_id: "{{ organization_user.org_id | default(omit) }}" + org_name: "{{ organization_user.org_name | default(omit) }}" + loop: "{{ grafana_organization_users }}" + loop_control: {loop_var: organization_user} tags: organization_user - name: Manage dashboard diff --git a/tasks/organization_users.yml b/tasks/organization_users.yml deleted file mode 100644 index 9b28e84..0000000 --- a/tasks/organization_users.yml +++ /dev/null @@ -1,61 +0,0 @@ ---- -- name: Manage organization users by org_id - community.grafana.grafana_organization_user: - url: "{{ grafana_url }}" - url_username: "{{ grafana_username }}" - url_password: "{{ grafana_password }}" - login: "{{ organization_user.login }}" - role: "{{ organization_user.role | default(omit) }}" - state: "{{ organization_user.state | default(omit) }}" - org_id: "{{ organization_user.org_id | default(omit) }}" - loop: "{{ grafana_organization_users | selectattr('org_id', 'defined') | list }}" - loop_control: {loop_var: organization_user} - -- name: Grafana organization API tasks - module_defaults: - ansible.builtin.uri: - url_username: "{{ grafana_username }}" - url_password: "{{ grafana_password }}" - force_basic_auth: true - return_content: true - when: grafana_organization_users | selectattr('org_name', 'defined') | list | length > 0 - block: - - name: Get organizations - ansible.builtin.uri: - url: "{{ grafana_url }}/api/orgs/name/{{ organization_names | urlencode }}" - loop: "{{ grafana_organization_users | map(attribute='org_name') | unique | list }}" - loop_control: {loop_var: organization_names} - register: _grafana_organizations - - - name: Get users - ansible.builtin.uri: - url: "{{ grafana_url }}/api/users/lookup?loginOrEmail={{ user.login | urlencode }}" - loop: "{{ grafana_organization_users | selectattr('state', 'defined') | selectattr('state', 'eq', 'absent') | list }}" - loop_control: {loop_var: user} - register: _grafana_users - - - name: Manage organization users by org_name - ansible.builtin.uri: - url: "{{ grafana_url }}/api/orgs/{{ _org_id }}/users{{ '/' ~ _user_id if _org_user_state == 'absent' else '' }}" - body: - loginOrEmail: "{{ organization_user.login }}" - role: "{{ organization_user.role | default(omit) }}" - body_format: json - method: "{{ 'DELETE' if _org_user_state == 'absent' else 'POST' }}" - status_code: ["200", "409"] - loop: "{{ grafana_organization_users | selectattr('org_name', 'defined') }}" - loop_control: {loop_var: organization_user} - vars: - _org_user_state: "{{ organization_user.state | default('') }}" - _org_id: "{{ _grafana_organizations.results | - map(attribute='json') | - selectattr('name', 'eq', organization_user.org_name) | - map(attribute='id') | - first }}" - _user_id: "{{ _grafana_users.results | - map(attribute='json') | - selectattr('login', 'eq', organization_user.login) | - map(attribute='id') | - first }}" - register: _grafana_organization_user - changed_when: _grafana_organization_user.json.message in ["User added to organization", "User removed from organization"] From 5aa9131ff7d30314aea7d66408fc1db9907ba1eb Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Wed, 29 Nov 2023 15:18:40 +0100 Subject: [PATCH 17/18] test(molecule): org users --- molecule/default/converge.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 6e3e513..a0489f8 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -24,6 +24,12 @@ - name: my_service - name: other_service + grafana_organization_users: + - login: testuser + org_id: 1 + - login: testuser + org_name: my_org + grafana_dashboards: - folder: my_service path: test_dashboard.json From 1693be3f06719d711bb7a01510b6c9adb45eabfd Mon Sep 17 00:00:00 2001 From: Nemental <15136847+Nemental@users.noreply.github.com> Date: Fri, 8 Dec 2023 09:13:47 +0100 Subject: [PATCH 18/18] fix: remove url params --- tasks/main.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/tasks/main.yml b/tasks/main.yml index 5c957f4..3796700 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -68,9 +68,6 @@ - name: Manage organization users community.grafana.grafana_organization_user: - url: "{{ grafana_url }}" - url_username: "{{ grafana_username }}" - url_password: "{{ grafana_password }}" login: "{{ organization_user.login }}" role: "{{ organization_user.role | default(omit) }}" state: "{{ organization_user.state | default(omit) }}"