From 61958b15b894711fd297736bc646c1dfc7348521 Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 28 Jul 2023 18:27:59 +0930 Subject: [PATCH] feat(config): Add General Settings Config from code !1 --- docs/projects/nfc_glpi/config_from_code.md | 24 +++++- tasks/api/api.yaml | 2 +- tasks/api/append-create-item.yaml | 35 +-------- tasks/api/config.yaml | 91 ++++++++++++++++++++++ tasks/api/search-add.yaml | 47 +++++++++++ tasks/main.yaml | 2 +- 6 files changed, 164 insertions(+), 37 deletions(-) create mode 100644 tasks/api/config.yaml create mode 100644 tasks/api/search-add.yaml diff --git a/docs/projects/nfc_glpi/config_from_code.md b/docs/projects/nfc_glpi/config_from_code.md index 7bb0803..6f7ce5a 100644 --- a/docs/projects/nfc_glpi/config_from_code.md +++ b/docs/projects/nfc_glpi/config_from_code.md @@ -6,13 +6,15 @@ template: project.html about: https://gitlab.com/nofusscomputing/projects/ansible/nfc_glpi --- -To configure GLPI using this role, the config/settings are saved as json files. The workflow to create the json files, is to (preferably within a test environment) make the required setting changes in GLPI using the GUI. one the changes have been made, conduct an API `GET` query to GLPI for the item you changed. The JSON body that is returned, is placed within the Config file (detailed below) under path `.body`. You must however, remove any fields that are not required, for example dynamic fields (fields that update themselves or are auto created) for example date fields. - +To configure GLPI using this role, the config/settings are saved as json files. The workflow to create the json files, is to (preferably within a test environment) make the required setting changes in GLPI using the GUI. one the changes have been made, conduct an API `GET` query to GLPI for the item you changed. The JSON body that is returned, is placed within the Config file (detailed below) under path `.body`. You must however, remove any fields that are not required, for example dynamic fields (fields that update themselves or are auto created) for example date fields. it's also recommended to remove the items `id` entry from the body, this option enables the updating and creation of the item by the name field. ## Config files Example -Each tab provides an example of the JSON file layout, including any additional variables. Any variable listed at path `.` that are empty strings, you would complete with the items name as it is exactly within GLPI. These fields are used to fetch the itm_id of the field by name. this enables having the config saved in a more human readable format. For example, for the field `entities_id` you would complete it as `"entities_id": "My entity name"`. +Each tab provides an example of the JSON file layout, including any additional variables. Any variable listed at path `.` that are empty strings, you would complete with the items name as it is exactly within GLPI. These fields are used to fetch the item_id of the field by name. This enables having the config saved in a more human readable format. For example, for the field `entities_id` you would complete it as `"entities_id": "My entity name"`. + +!!! tip + If you leave the item ID in the config file under path `.body.id`, the item that matches this ID, will be updated, not the item matching the name. === "AuthLDAP" @@ -27,6 +29,22 @@ Each tab provides an example of the JSON file layout, including any additional v ``` +=== "Config (GLPI General Settings)" + + This config file contains the settings found in `General Settings`. The full API JSON response is added to the body. When this file is processed, each individual item is added via the API without using the `id` as found in the JSON file. This is done as the ID's can change, so the workflow includes a step that matches the config item name to the found id in the database, then patches with the values from the JSON file. + + ``` json title="example.json" linenums="1" + { + "api_path": "Config", + "body": [ + // JSON from API Query the full response (see note below) + ] + } + ``` + + !!! info + The structure of this JSON file is different than the rest. The body is a **list** of **ALL** of the Config options. This includes the item ID. it was done this way, so that only one API query is required to export all config options. + === "Entity" ``` json title="example.json" linenums="1" diff --git a/tasks/api/api.yaml b/tasks/api/api.yaml index f5e43f5..f11cb5d 100644 --- a/tasks/api/api.yaml +++ b/tasks/api/api.yaml @@ -11,7 +11,7 @@ - name: Append/Create Item ansible.builtin.include_tasks: - file: append-create-item.yaml + file: search-add.yaml loop: "{{ glpi_config_as_code_json }}" diff --git a/tasks/api/append-create-item.yaml b/tasks/api/append-create-item.yaml index a862917..0e479e2 100644 --- a/tasks/api/append-create-item.yaml +++ b/tasks/api/append-create-item.yaml @@ -1,39 +1,10 @@ --- -- name: Create item_body - ansible.builtin.set_fact: - item_body: "{{ item.body }}" - no_log: true - - - name: Search item_id ansible.builtin.include_tasks: file: api/search/item_id.yaml - when: not item.body.id is defined - - -- name: Search entities_id - ansible.builtin.include_tasks: - file: api/search/entities_id.yaml - when: item.entities_id is defined - - -- name: Search tickettemplates_id_demand - ansible.builtin.include_tasks: - file: api/search/tickettemplates_id_demand.yaml - when: item.tickettemplates_id_demand is defined - - -- name: Search itilcategories_id - ansible.builtin.include_tasks: - file: api/search/itilcategories_id.yaml - when: item.itilcategories_id is defined - - -- name: Search users_id - ansible.builtin.include_tasks: - file: api/search/users_id.yaml - when: item.users_id is defined + when: > + not item.body.id is defined - name: Show Body @@ -59,7 +30,7 @@ - name: Update Item ansible.builtin.uri: - url: "http://{{ glpi.host }}/apirest.php/{{ item.api_path }}/{{ item_body.id }}" + url: "http://{{ glpi.host }}/apirest.php/{{ item.api_path }}{% if item.api_path != 'Config' %}/{{ item_body.id }}{% endif %}" method: "PATCH" return_content: true body: "{\"input\": {{ item_body | from_yaml | to_json }} }" diff --git a/tasks/api/config.yaml b/tasks/api/config.yaml new file mode 100644 index 0000000..fb6fc1e --- /dev/null +++ b/tasks/api/config.yaml @@ -0,0 +1,91 @@ +--- + +- name: Show {{ list_item.body.name }} + ansible.builtin.debug: + msg: "{{ list_item }}" + +- name: Fetch ID for {{ list_item.body.name }} + ansible.builtin.uri: + url: "http://{{ glpi.host }}/apirest.php/{{ item.api_path }}?searchText[name]={{ list_item.body.name | urlencode }}" + method: "GET" + return_content: true + body: '' + # status_code: "{{ item.status_code | from_yaml | list }}" + status_code: [200, 201] + headers: + App-Token: "{{ glpi.app_token }}" + Session-Token: "{{ glpi.session.valid_id }}" + body_format: json + no_log: true + register: glpi_search + + +- name: Build API Body for {{ list_item.body.name }} + ansible.builtin.set_fact: + config_item: + api_path: "{{ list_item.api_path }}" + body: + context: "{{ list_item.body.context }}" + name: "{{ list_item.body.name }}" + value: "{{ list_item.body.value }}" + when: glpi_search.json | length | int == 0 + no_log: true + + +- name: Build API Body (with ID) for {{ list_item.body.name }} + ansible.builtin.set_fact: + config_item: + api_path: "{{ list_item.api_path }}" + body: + id: "{% for found_id in glpi_search.json %}{%if list_item.body.name == found_id.name %}{{ found_id.id }}{% endif %}{% endfor %}" + context: "{{ list_item.body.context }}" + name: "{{ list_item.body.name }}" + value: "{{ list_item.body.value }}" + when: glpi_search.json | length | int > 0 + no_log: true + + +- name: "Item [{{ config_item.body.id + ']: ' + config_item.body.name }}" + ansible.builtin.debug: + msg: "{{ config_item }}" + when: config_item is defined + + +# ToDo: figure out why cant create item????? + +# - name: Create Config Item +# ansible.builtin.uri: +# url: "http://{{ glpi.host }}/apirest.php/{{ config_item.api_path }}" +# method: "POST" +# return_content: true +# body: "{\"input\": {{ config_item.body | from_yaml | to_json }} }" +# status_code: [200, 201] +# headers: +# App-Token: "{{ glpi.app_token }}" +# Session-Token: "{{ glpi.session.valid_id }}" +# body_format: json +# # no_log: true +# when: not config_item.body.id is defined + + +- name: Update Config Item + ansible.builtin.uri: + url: "http://{{ glpi.host }}/apirest.php/{{ item.api_path }}/{{ config_item.body.id }}" + method: "PATCH" + return_content: true + body: "{\"input\": {{ config_item.body | from_yaml | to_json }} }" + status_code: [200, 201] + headers: + App-Token: "{{ glpi.app_token }}" + Session-Token: "{{ glpi.session.valid_id }}" + body_format: json + no_log: true + when: config_item.body.id is defined + + +- name: Clear temp vars + ansible.builtin.set_fact: + config_item: {} + glpi_search: {} + list_item: {} + no_log: true diff --git a/tasks/api/search-add.yaml b/tasks/api/search-add.yaml new file mode 100644 index 0000000..3234ec8 --- /dev/null +++ b/tasks/api/search-add.yaml @@ -0,0 +1,47 @@ +--- + +- name: Create item_body + ansible.builtin.set_fact: + item_body: "{{ item.body }}" + no_log: true + + +- name: Append/Create Item + ansible.builtin.include_tasks: + file: api/append-create-item.yaml + when: not item.api_path == 'Config' + + +- name: Config Items to skip + ansible.builtin.set_fact: + skip_config: + - cas_version + - dbversion + - _dbslave_status + - schema_version + - version + when: item.api_path == 'Config' + + +- name: Config + ansible.builtin.include_tasks: + file: api/config.yaml + when: > + item.api_path == 'Config' + and + not sub_item.name in skip_config + loop: "{{ item_body }}" + loop_control: + loop_var: sub_item + vars: + list_item: + api_path: "{{ item.api_path }}" + body: + context: "{{ sub_item.context }}" + name: "{{ sub_item.name }}" + value: "{{ sub_item.value | default('') }}" + + +- name: Clear temp vars + ansible.builtin.set_fact: + item_body: {} diff --git a/tasks/main.yaml b/tasks/main.yaml index db78c4f..6461bab 100644 --- a/tasks/main.yaml +++ b/tasks/main.yaml @@ -37,4 +37,4 @@ apply: tags: - always - when: glpi_config_as_code_json length | int > 0 + when: glpi_config_as_code_json | length | int > 0