diff --git a/.cz.yaml b/.cz.yaml new file mode 100644 index 0000000..62b2ada --- /dev/null +++ b/.cz.yaml @@ -0,0 +1,7 @@ +commitizen: + bump_message: "build(version): bump version $current_version \u2192 $new_version" + changelog_incremental: false + name: cz_conventional_commits + tag_format: $major.$minor.$patch$prerelease + update_changelog_on_bump: true + version: 0.0.1 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..71f2c7b --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,15 @@ +--- + +include: + - project: nofusscomputing/projects/gitlab-ci + ref: development + file: + - .gitlab-ci_common.yaml + - template/automagic.gitlab-ci.yaml + + +variables: + MY_PROJECT_ID: "48046854" + GIT_SYNC_URL: "https://$GITHUB_USERNAME_ROBOT:$GITHUB_TOKEN_ROBOT@github.com/NoFussComputing/ansible_role_glpi.git" + PAGES_ENVIRONMENT_PATH: projects/nfc_glpi/ + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..de6bfdd --- /dev/null +++ b/.gitmodules @@ -0,0 +1,8 @@ +[submodule "gitlab-ci"] + path = gitlab-ci + url = https://gitlab.com/nofusscomputing/projects/gitlab-ci.git + branch = development +[submodule "website-template"] + path = website-template + url = https://gitlab.com/nofusscomputing/infrastructure/website-template.git + branch = development diff --git a/.nfc_automation.yaml b/.nfc_automation.yaml new file mode 100644 index 0000000..077d7f4 --- /dev/null +++ b/.nfc_automation.yaml @@ -0,0 +1,8 @@ +--- + +role_git_conf: + gitlab: + submodule_branch: "development" + default_branch: development + mr_labels: ~"type::automation" ~"impact::0" ~"priority::0" + auto_merge: true diff --git a/defaults/main.yaml b/defaults/main.yaml new file mode 100644 index 0000000..1a1d295 --- /dev/null +++ b/defaults/main.yaml @@ -0,0 +1,51 @@ +--- +# directory_logrotate_config: /etc/logrotate.d +install_glpi: 'true' +glpi_installed: false +# logfile_max_size: 10 # must be specified in MB (Mega Bytes) +# logrotate_configuration: [] # Global var for usage within group/host vars + +docker_image_name_glpi: nofusscomputing/docker-glpi +docker_image_tag_glpi: dev + +docker_container_name_glpi: glpi +# mysql_unix_socket: /run/mysql/mariadb/mysqld.sock +mysql_unix_socket: /var/lib/docker/volumes/socket-mysql/_data/mysqld.sock +mysql_login_user: root +mysql_login_password: admin + +glpi_plugins: + - filename: fail2ban_1.0.2-1.upstream1_all.deb + #url: https://github.com/pluginsGLPI/formcreator/releases/download/2.13.6/glpi-formcreator-2.13.6.tar.bz2 + url: https://api.github.com/repos/pluginsGLPI/formcreator/releases/tags/2.13.6 + + - filename: glpi-glpiinventory-1.2.3.tar.bz2 + #url: https://github.com/glpi-project/glpi-inventory-plugin/releases/download/1.2.3/glpi-glpiinventory-1.2.3.tar.bz2 + url: https://api.github.com/repos/glpi-project/glpi-inventory-plugin/releases/tags/1.2.3 + + # - filename: glpi-actualtime-2.1.0.tar.tgz + # url: https://api.github.com/repos/ticgal/actualtime/releases/tags/2.1.0/glpi-actualtime-2.1.0.tar.tgz + + +mysql_database_glpi: glpi + +# Configuration Example +# logrotate: +# - name: docker # Mandatory, used as logrotate difinition file name +# path: '/var/lib/docker/containers/*/*.log' # Mandatory, path to the logfile +# su: ingress ingress # Optional,, string user and group for log permissions +# interval: daily # optional example daily, weekly, monthly default=daily +# keep: # Optional, int, How many logs to keep default=7 +# size: 10 # Optional, max size of logfile in Mega Bytes. DONT specify unit. default={{}} +# compress: # Optional, bool default=true +# delaycompress: # Optional, bool, delay logfile compression default=true +# postrotate: 'docker restart $(docker ps -q)' # Optional, Command to run post rotate default=not defined +# create: # Optional, default=not defined +# mode: 640 # Mandatory, filemode +# owner: root # Mandatory, logfile owner +# group: adm # Mandatory, logfile group owner + + + +glpi_config_as_code_json: [] +search_items: [] diff --git a/docs/articles/index.md b/docs/articles/index.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/contact.md b/docs/contact.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/operations/index.md b/docs/operations/index.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/projects/index.md b/docs/projects/index.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/projects/nfc_glpi/config_from_code.md b/docs/projects/nfc_glpi/config_from_code.md new file mode 100644 index 0000000..2a6b647 --- /dev/null +++ b/docs/projects/nfc_glpi/config_from_code.md @@ -0,0 +1,170 @@ +--- +title: GLPI Config as code +description: How to use No Fuss Computings Ansible role to configure GLPI from configuration as code. +date: 2023-07-28 +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. once 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. + +As the export process is manual to create the json files, it is possible that errors could occur. another side effect is that when updating an item, when checking it into an SCM (git for example), that the commit may contain more than the item that changed. This is planned to be rectified in [gitlab-#1](https://gitlab.com/nofusscomputing/projects/ansible/nfc_glpi/-/issues/1). + +!!! warning + To utilise the config from json files, it's important that any configurable item from json files, that it's name is unique for that item type within GLPI. This is due to the feature "find item_id by name" i.e. you can't have two items named `my name` and `my name` of type `x`, even if in different entities. + + +## Config files Example + +Each tab provides an example of the JSON file layout, including any additional variables. Variable listed at path `.`, with the exception of `api_path`, `body` or have asuffix of `_` are provided to use that items name. These fields are used to fetch the item_id of the field by name. available fields are: + +- entities_id + +- groups_id + +- item_id + +- itilcategories_id + +- tickettemplates_id_demand + +- tickettemplates_id + +- users_id + + +For example, to have an item placed in the entity `NoFussComputing` provided value would be `"entities_id": "NoFussComputing"`. As part of the item workflow a search for an entity named `NoFussComputing` is conducted, and if found, adds it's `entity_id` to path `.body.entities_id: {entity_id}`. + + +!!! 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" + + ``` json title="example.json" linenums="1" + + { + "api_path": "AuthLDAP", + "body": { + // JSON from API Query + } + } + + ``` + +=== "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. + + !!! info "Further Information" + Any config item that does not contain a value field, is excluded from being added or updated. In addition, the following items by name, are excluded + + ``` yaml title="tasks/api/excluded_config.yaml" linenums="1" + + --8<-- "tasks/api/excluded_config.yaml" + + ``` + +=== "Entity" + + ``` json title="example.json" linenums="1" + + { + "api_path": "Entity", + "entities_id": "", + "body": { + // JSON from API Query + } + } + + ``` + +=== "ITILCategory" + + ``` json title="example.json" linenums="1" + + { + "api_path": "ITILCategory", + "users_id": "", + "itilcategories_id": "", + "entities_id": "", + "tickettemplates_id_demand": "", + "body": { + // JSON from API Query + } + } + + ``` + +=== "Profile" + + ``` json title="example.json" linenums="1" + + { + "api_path": "Profile", + "body": { + // JSON from API Query + } + } + + ``` + +=== "TicketTemplate" + + This config file covers all parts of a ticket template. with this template you can create and update an existing ticket template. + + !!! warning + Assosiated Items do not get updated or removed. They will be added if they don't exist. No checks are done for more assosiated items then are specified in the template. + + ``` json title="example.json" linenums="1" + + { + "api_path": "TicketTemplate", + "entities_id": "", + "body": { + // JSON from API Query + }, + "_TicketTemplateMandatoryField": [ + + // JSON from API Query path TicketTemplate/{ticket_template_id}/TicketTemplateMandatoryField + ], + "_TicketTemplatePredefinedField": [ + + // JSON from API Query path TicketTemplate/{ticket_template_id}/TicketTemplatePredefinedField + + ], + "_TicketTemplateHiddenField": [ + + // JSON from API Query path TicketTemplate/{ticket_template_id}/TicketTemplateHiddenField + + ] + } + + ``` + + Sub-items to the ticket are `TicketTemplateMandatoryField`, `TicketTemplatePredefinedField` and `TicketTemplateHiddenField` and are at json path `._{sub-item}`. These items are a **list of dicts** and can contain the `id` of the item, however it is ignored as the update is base off of `tickettemplates_id`, `num` for all and `tickettemplates_id`, `num` and `value` for `num=13` which is an assosiated item. With the exception of the latter, all of these values will be updated if they exist. + + +With the config files structured as per the examples, within your playbook(s), load the json files in a list of json objects using variable `glpi_config_as_code_json` + +example + +``` yaml title="my_vars.yaml" linenums="1" + +glpi_config_as_code_json: + - "{{ lookup('file', '/workdir/files/glpi/ITILCategory-new-ldap-user.json') | from_json }}" + - "{{ lookup('file', '/workdir/files/glpi/LDAPAuth-local_ldap.json') | from_json }}" + +``` diff --git a/docs/projects/nfc_glpi/index.md b/docs/projects/nfc_glpi/index.md new file mode 100644 index 0000000..fed6c82 --- /dev/null +++ b/docs/projects/nfc_glpi/index.md @@ -0,0 +1,25 @@ +--- +title: nfc_glpi - Ansible Role +description: How to use No Fuss Computings Ansible role to manage GLPI from configuration as code. +date: 2023-07-28 +template: project.html +about: https://gitlab.com/nofusscomputing/projects/ansible/nfc_glpi +--- + +This Ansible role is designed to manage GLPI specifically installation and configuration. + + +## Features + +- install GLPI using our [docker container](https://gitlab.com/nofusscomputing/projects/docker-glpi) + +- [Configure using Config from Code](config_from_code.md) + + +## Default Variables + +``` yaml title="defaults/main.yaml" linenums="1" + +--8<-- "defaults/main.yaml" + +``` diff --git a/gitlab-ci b/gitlab-ci new file mode 160000 index 0000000..975de7a --- /dev/null +++ b/gitlab-ci @@ -0,0 +1 @@ +Subproject commit 975de7aca210667d1e93d02a4036ca4ae70808ff diff --git a/handlers/main.yaml b/handlers/main.yaml new file mode 100644 index 0000000..65abc11 --- /dev/null +++ b/handlers/main.yaml @@ -0,0 +1,29 @@ +--- +# - name: Log Rotate Configuration files +# ansible.builtin.template: +# src: definition.j2 +# dest: "{{ directory_logrotate_config }}/{{ item.name }}" +# owner: root +# mode: '0644' +# force: true +# loop: "{{ logrotate_configuration }}" +# listen: 'configure_logrotate' +# notify: restart_logrotate +# when: logrotate_installed | bool + + +# - name: Restart logrotate +# ansible.builtin.service: +# name: logrotate +# state: restarted +# listen: restart_logrotate +# when: logrotate_installed | bool + +- name: Restart GLPI + community.docker.docker_container: + name: "{{ docker_container_name_glpi }}" + state: started + restart: true + listen: restart_glpi + when: > + glpi_installed | bool diff --git a/meta/main.yaml b/meta/main.yaml new file mode 100644 index 0000000..31ab5e5 --- /dev/null +++ b/meta/main.yaml @@ -0,0 +1,13 @@ +galaxy_info: + role_name: nfc_glpi + author: No Fuss Computing + description: |- + A universal role to install and configure a glpi. + + This role is also desiged so that it can be included within other roles. + + issue_tracker_url: https://gitlab.com/nofusscomputing/projects/ansible/nfc_glpi + + license: https://gitlab.com/nofusscomputing/projects/ansible/nfc_glpi/-/blob/master/LICENSE + + min_ansible_version: '1.2' diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..984fab6 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,33 @@ +INHERIT: website-template/mkdocs.yml + +docs_dir: 'docs' + +repo_name: nfc_glpi +repo_url: https://gitlab.com/nofusscomputing/projects/ansible/nfc_glpi +edit_uri: '/-/ide/project/nofusscomputing/projects/ansible/nfc_glpi/edit/development/-/docs/' + +nav: +- Home: index.md + +- Articles: + + - articles/index.md + +- Projects: + + - projects/index.md + + - Ansible Roles: + + - GLPI: + + - projects/nfc_glpi/index.md + + - projects/nfc_glpi/config_from_code.md + +- Operations: + + - operations/index.md + +- Contact Us: contact.md + diff --git a/tasks/api/api.yaml b/tasks/api/api.yaml new file mode 100644 index 0000000..f11cb5d --- /dev/null +++ b/tasks/api/api.yaml @@ -0,0 +1,24 @@ +--- +- name: Always End Session + block: + + + - name: Start Session + ansible.builtin.include_tasks: + file: api/session-create.yaml + when: glpi.api.session | default('') == '' + + + - name: Append/Create Item + ansible.builtin.include_tasks: + file: search-add.yaml + loop: "{{ glpi_config_as_code_json }}" + + + always: + + + - name: End Session + ansible.builtin.include_tasks: + file: api/session-end.yaml + when: glpi_session_get.status | default(0) | int == 200 diff --git a/tasks/api/append-create-item.yaml b/tasks/api/append-create-item.yaml new file mode 100644 index 0000000..ef6af18 --- /dev/null +++ b/tasks/api/append-create-item.yaml @@ -0,0 +1,73 @@ +--- + +- name: Show item + ansible.builtin.debug: + msg: "{{ item }}" + +- name: Create item_body + ansible.builtin.set_fact: + item_body: "{{ item.body }}" + no_log: true + + +- name: Search for item IDs + ansible.builtin.include_tasks: + file: api/search.yaml + + +- name: Show Body + ansible.builtin.debug: + msg: "{{ item_body }}" + when: item_body is defined + + +- name: Create Item + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/{{ item.api_path }}{% if item.sub_path is defined %}/{{ item.sub_path }}{% endif %}" + method: "POST" + return_content: true + body: "{\"input\": {{ 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 + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + no_log: true + register: create_item + when: > + not item_body.id is defined + + +- name: Update Item + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/{{ item.api_path }}{% if item.sub_path is defined %}/{{ item.sub_path }}{% else %}{% if item.api_path != 'Config' %}/{{ item_body.id | default('') }}{% endif %}{% endif %}" + method: "PATCH" + return_content: true + body: "{\"input\": {{ 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 + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + no_log: true + register: update_item + when: item_body.id is defined + + +- name: Fail on no action + ansible.builtin.fail: + msg: No action carried out, stop. + when: > + update_item.skipped | default(false) | bool + and + create_item.skipped | default(false) | bool + + +- name: Clear temp vars + ansible.builtin.set_fact: + item_body: {} + create_item: {} + update_item: {} + no_log: true diff --git a/tasks/api/config.yaml b/tasks/api/config.yaml new file mode 100644 index 0000000..306cc07 --- /dev/null +++ b/tasks/api/config.yaml @@ -0,0 +1,100 @@ +--- + +- name: Fetch ID for {{ list_item.body.name }} + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/{{ item.api_path }}?searchText[name]={{ list_item.body.name | urlencode }}" + method: "GET" + return_content: true + body: '' + status_code: [200, 201] + headers: + App-Token: "{{ glpi.app_token }}" + Session-Token: "{{ glpi.session.valid_id }}" + body_format: json + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + 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: Remove Empty ID from body + 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: config_item.body.id | default('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_protocol | default('https') | string }}://{{ 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 + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + 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/excluded_config.yaml b/tasks/api/excluded_config.yaml new file mode 100644 index 0000000..efcb4cc --- /dev/null +++ b/tasks/api/excluded_config.yaml @@ -0,0 +1,21 @@ +--- +# +# Config items excluded from Adding/Updating. +# +# Each list item is the name of the config item. +# +- name: Config Items to skip + ansible.builtin.set_fact: + skip_config: + - cas_version + - dbversion + - _dbslave_status + - init_all + - instance_uuid + - notification_uuid + - proxy_passwd + - registration_uuid + - schema_version + - smtp_passwd + - version + when: item.api_path == 'Config' diff --git a/tasks/api/search-add.yaml b/tasks/api/search-add.yaml new file mode 100644 index 0000000..31a1b34 --- /dev/null +++ b/tasks/api/search-add.yaml @@ -0,0 +1,45 @@ +--- + +- name: Ticket Template + ansible.builtin.include_tasks: + file: api/ticket_template.yaml + when: item.api_path == 'TicketTemplate' + + +- name: Append/Create Item + ansible.builtin.include_tasks: + file: api/append-create-item.yaml + when: > + not item.api_path == 'Config' + and + not item.api_path == 'TicketTemplate' + + +- name: Config Items to skip + ansible.builtin.import_tasks: + file: api/excluded_config.yaml + + +- name: Add/Update GLPI Config + ansible.builtin.include_tasks: + file: api/config.yaml + when: > + not sub_item.name in skip_config + and + sub_item.value is defined + loop: "{% if item.api_path == 'Config' %}{{ item.body }}{% else %}{{ [] }}{% endif %}" + 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 }}" + + +- name: Clear temp vars + ansible.builtin.set_fact: + item_body: {} + no_log: true diff --git a/tasks/api/search.yaml b/tasks/api/search.yaml new file mode 100644 index 0000000..97998b7 --- /dev/null +++ b/tasks/api/search.yaml @@ -0,0 +1,42 @@ +--- + +- 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 groups_id + ansible.builtin.include_tasks: + file: api/search/groups_id.yaml + when: item.groups_id is defined + + +- name: Search itilcategories_id + ansible.builtin.include_tasks: + file: api/search/itilcategories_id.yaml + when: item.itilcategories_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 tickettemplates_id + ansible.builtin.include_tasks: + file: api/search/tickettemplates_id.yaml + when: item.tickettemplates_id is defined + + +- name: Search users_id + ansible.builtin.include_tasks: + file: api/search/users_id.yaml + when: item.users_id is defined diff --git a/tasks/api/search/entities_id.yaml b/tasks/api/search/entities_id.yaml new file mode 100644 index 0000000..de0c3c2 --- /dev/null +++ b/tasks/api/search/entities_id.yaml @@ -0,0 +1,54 @@ +--- +- name: Fetch entities_id + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/Entity?searchText[name]={{ item.entities_id | 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 + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + register: glpi_search + no_log: true + + +- name: Iterate over results for ID search + ansible.builtin.shell: + cmd: | + cat < + glpi_search.json | length | int > 0 + + +- name: Set entities_id + ansible.builtin.set_fact: + new_data: "{{ itarate_id.stdout | from_yaml }}" + when: itarate_id.stdout | default({}) | length | int > 0 + + +- name: Append entities_id + ansible.builtin.set_fact: + item_body: "{{ item_body | ansible.builtin.combine(new_data | default({})) }}" + glpi_search: {} + itarate_id: {} + new_data: {} + no_log: true diff --git a/tasks/api/search/groups_id.yaml b/tasks/api/search/groups_id.yaml new file mode 100644 index 0000000..2f33281 --- /dev/null +++ b/tasks/api/search/groups_id.yaml @@ -0,0 +1,54 @@ +--- + +- name: Fetch users_id + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/Group?searchText[name]={{ item.groups_id | urlencode }}" + method: "GET" + return_content: true + body: '' + status_code: [200, 201] + headers: + App-Token: "{{ glpi.app_token }}" + Session-Token: "{{ glpi.session.valid_id }}" + body_format: json + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + register: glpi_search + no_log: true + + +- name: Iterate over results for ID search + ansible.builtin.shell: + cmd: | + cat < + glpi_search.json | length | int > 0 + + +- name: Set groups_id + ansible.builtin.set_fact: + new_data: "{{ itarate_id.stdout | from_yaml }}" + when: itarate_id.stdout | default({}) | length | int > 0 + + +- name: Append groups (have item_body) + ansible.builtin.set_fact: + item_body: "{{ item_body | ansible.builtin.combine(new_data | default({})) }}" + glpi_search: {} + itarate_id: {} + new_data: {} + no_log: true diff --git a/tasks/api/search/item_id.yaml b/tasks/api/search/item_id.yaml new file mode 100644 index 0000000..1ec44a8 --- /dev/null +++ b/tasks/api/search/item_id.yaml @@ -0,0 +1,122 @@ +--- +- name: Find Item ID + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/{{ item.api_path }}{% if item.sub_path is defined %}/{{ item.sub_path }}{% endif%}{% if search_items | length | int > 0%}?{% for search in search_items %}searchText[{{ search.name }}]={{ search.value | urlencode }}&{% endfor %}{% else%}?searchText[name]={{ item.body.name | urlencode }}{% endif %}" + 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 + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + register: glpi_search + no_log: true + + +- name: Set id + ansible.builtin.set_fact: + new_data: + id: "{{ glpi_search.json[0].id | int }}" + when: glpi_search.json | length | int == 1 + + +- name: Iterate over results for TicketTemplateMandatoryField id/TicketTemplateHiddenField + ansible.builtin.shell: + cmd: | + cat < + glpi_search.json | length | int > 1 + and + ( + 'TicketTemplateMandatoryField' in item.sub_path | default('') + or + 'TicketTemplateHiddenField' in item.sub_path | default('') + ) + + +- name: Set iterate id + ansible.builtin.set_fact: + new_data: "{{ itarate_id.stdout | from_yaml }}" + when: itarate_id.stdout is defined + + +- name: Iterate over results for TicketTemplatePredefinedField id + ansible.builtin.shell: + cmd: | + cat < + glpi_search.json | length | int > 1 + and + 'TicketTemplatePredefinedField' in item.sub_path | default('') + + +- name: Set iterate id + ansible.builtin.set_fact: + new_data: "{{ itarate_id.stdout | from_yaml }}" + when: itarate_id.stdout is defined + + +- name: Item_id fact Cleanup + ansible.builtin.set_fact: + item_body: "{{ item_body | ansible.builtin.combine(new_data | default({})) }}" + glpi_search: {} + itarate_id: {} + new_data: {} + no_log: true diff --git a/tasks/api/search/itilcategories_id.yaml b/tasks/api/search/itilcategories_id.yaml new file mode 100644 index 0000000..6be3a5b --- /dev/null +++ b/tasks/api/search/itilcategories_id.yaml @@ -0,0 +1,54 @@ +--- +- name: Fetch itilcategories_id + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/ITILCategory?searchText[name]={{ item.itilcategories_id | 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 + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + register: glpi_search + no_log: true + + +- name: Iterate over results for ID search + ansible.builtin.shell: + cmd: | + cat < + glpi_search.json | length | int > 0 + + +- name: Set itilcategories_id + ansible.builtin.set_fact: + new_data: "{{ itarate_id.stdout | from_yaml }}" + when: itarate_id.stdout | default({}) | length | int > 0 + + +- name: Append itilcategories_id + ansible.builtin.set_fact: + item_body: "{{ item_body | ansible.builtin.combine(new_data | default({})) }}" + glpi_search: {} + itarate_id: {} + new_data: {} + no_log: true diff --git a/tasks/api/search/tickettemplates_id.yaml b/tasks/api/search/tickettemplates_id.yaml new file mode 100644 index 0000000..44b14ec --- /dev/null +++ b/tasks/api/search/tickettemplates_id.yaml @@ -0,0 +1,54 @@ +--- +- name: Fetch tickettemplates_id + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/TicketTemplate?searchText[name]={{ item.tickettemplates_id | urlencode }}" + method: "GET" + return_content: true + body: '' + status_code: [200, 201] + headers: + App-Token: "{{ glpi.app_token }}" + Session-Token: "{{ glpi.session.valid_id }}" + body_format: json + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + register: glpi_search + no_log: true + + +- name: Iterate over results for ID search + ansible.builtin.shell: + cmd: | + cat < + glpi_search.json | length | int > 0 + + +- name: Set tickettemplates_id + ansible.builtin.set_fact: + new_data: "{{ itarate_id.stdout | from_yaml }}" + when: itarate_id.stdout | default({}) | length | int > 0 + + +- name: Append tickettemplates_id + ansible.builtin.set_fact: + item_body: "{{ item_body | ansible.builtin.combine(new_data | default({})) }}" + tickettemplates_id: "{{ new_data.tickettemplates_id | default(omit) | int }}" + glpi_search: {} + itarate_id: {} + new_data: {} + no_log: true diff --git a/tasks/api/search/tickettemplates_id_demand.yaml b/tasks/api/search/tickettemplates_id_demand.yaml new file mode 100644 index 0000000..dc8e25f --- /dev/null +++ b/tasks/api/search/tickettemplates_id_demand.yaml @@ -0,0 +1,54 @@ +--- +- name: Fetch tickettemplates_id_demand + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/TicketTemplate?searchText[name]={{ item.tickettemplates_id_demand | 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 + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + register: glpi_search + no_log: true + + +- name: Iterate over results for ID search + ansible.builtin.shell: + cmd: | + cat < + glpi_search.json | length | int > 0 + + +- name: Set tickettemplates_id_demand + ansible.builtin.set_fact: + new_data: "{{ itarate_id.stdout | from_yaml }}" + when: itarate_id.stdout | default({}) | length | int > 0 + + +- name: Append tickettemplates_id_demand + ansible.builtin.set_fact: + item_body: "{{ item_body | ansible.builtin.combine(new_data | default({})) }}" + glpi_search: {} + itarate_id: {} + new_data: {} + no_log: true diff --git a/tasks/api/search/users_id.yaml b/tasks/api/search/users_id.yaml new file mode 100644 index 0000000..31daa45 --- /dev/null +++ b/tasks/api/search/users_id.yaml @@ -0,0 +1,55 @@ +--- + +- name: Fetch users_id + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/User?searchText[name]={{ item.users_id | 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 + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + register: glpi_search + no_log: true + + +- name: Iterate over results for ID search + ansible.builtin.shell: + cmd: | + cat < + glpi_search.json | length | int > 0 + + +- name: Set users_id + ansible.builtin.set_fact: + new_data: "{{ itarate_id.stdout | from_yaml }}" + when: itarate_id.stdout | default({}) | length | int > 0 + + +- name: Append users_id (have item_body) + ansible.builtin.set_fact: + item_body: "{{ item_body | ansible.builtin.combine(new_data | default({})) }}" + glpi_search: {} + itarate_id: {} + new_data: {} + no_log: true diff --git a/tasks/api/session-create.yaml b/tasks/api/session-create.yaml new file mode 100644 index 0000000..00c7b77 --- /dev/null +++ b/tasks/api/session-create.yaml @@ -0,0 +1,30 @@ +--- +- name: Fetch API Session Token + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/initSession?get_full_session=true" + method: GET + return_content: true + body: "" + status_code: 200 + headers: + App-Token: "{{ glpi.app_token }}" + Authorization: "user_token {{ glpi.user_token }}" + body_format: json + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + register: glpi_session_get + no_log: true + tags: + - always + + +- name: Session Data + ansible.builtin.set_fact: + glpi_session: + session: "{{ glpi_session_get.json.session }}" + no_log: true + + +- name: Session fact + ansible.builtin.set_fact: + glpi: "{{ glpi | ansible.builtin.combine(glpi_session) }}" + no_log: true diff --git a/tasks/api/session-end.yaml b/tasks/api/session-end.yaml new file mode 100644 index 0000000..54a5d5f --- /dev/null +++ b/tasks/api/session-end.yaml @@ -0,0 +1,14 @@ +--- +- name: End API Session + ansible.builtin.uri: + url: "{{ http_protocol | default('https') | string }}://{{ glpi.host }}/apirest.php/killSession" + method: GET + return_content: true + body: '' + status_code: 200 + headers: + App-Token: "{{ glpi.app_token }}" + Session-Token: "{{ glpi_session_get.json.session.valid_id }}" + body_format: json + validate_certs: "{{ glpi.validate_certs | default(true) | bool }}" + no_log: true diff --git a/tasks/api/ticket_template.yaml b/tasks/api/ticket_template.yaml new file mode 100644 index 0000000..b0e2387 --- /dev/null +++ b/tasks/api/ticket_template.yaml @@ -0,0 +1,103 @@ +--- + +- name: Template item + ansible.builtin.set_fact: + template_item: "{{ item }}" + + +- name: Append/Create TicketTemplate + ansible.builtin.include_tasks: + file: api/append-create-item.yaml + when: item.api_path == 'TicketTemplate' + vars: + item: + api_path: TicketTemplate + entities_id: "{{ template_item.entities_id }}" + body: "{{ template_item.body }}" + + +- name: Search tickettemplates_id + ansible.builtin.include_tasks: + file: api/search/tickettemplates_id.yaml + vars: + item: + tickettemplates_id: "{{ template_item.body.name }}" + + +- name: Append/Create Ticket Template Mandatory Fields + ansible.builtin.include_tasks: + file: api/append-create-item.yaml + when: > + template_item._TicketTemplateMandatoryField is defined + and + template_item._TicketTemplateMandatoryField | length | int > 0 + loop: "{{ template_item._TicketTemplateMandatoryField }}" + loop_control: + loop_var: sub_item + vars: + search_items: + - name: tickettemplates_id + value: "{{ tickettemplates_id }}" + - name: num + value: "{{ sub_item.num }}" + item: + api_path: TicketTemplate + sub_path: "{{ tickettemplates_id }}/TicketTemplateMandatoryField" + body: + num: "{{ sub_item.num }}" + tickettemplates_id: "{{ tickettemplates_id | int }}" + + +- name: Append/Create Ticket Template Predefined Fields + ansible.builtin.include_tasks: + file: api/append-create-item.yaml + when: > + template_item._TicketTemplatePredefinedField is defined + and + template_item._TicketTemplatePredefinedField | length | int > 0 + loop: "{{ template_item._TicketTemplatePredefinedField }}" + loop_control: + loop_var: sub_item + vars: + search_items: + - name: tickettemplates_id + value: "{{ tickettemplates_id }}" + - name: num + value: "{{ sub_item.num }}" + item: + api_path: TicketTemplate + sub_path: "{{ tickettemplates_id }}/TicketTemplatePredefinedField" + body: + num: "{{ sub_item.num | int }}" + tickettemplates_id: "{{ tickettemplates_id | int }}" + value: "{{ sub_item.value | string }}" + + +- name: Append/Create Ticket Template Hidden Fields + ansible.builtin.include_tasks: + file: api/append-create-item.yaml + when: > + template_item._TicketTemplateHiddenField is defined + and + template_item._TicketTemplateHiddenField | length | int > 0 + loop: "{{ template_item._TicketTemplateHiddenField }}" + loop_control: + loop_var: sub_item + vars: + search_items: + - name: tickettemplates_id + value: "{{ tickettemplates_id }}" + - name: num + value: "{{ sub_item.num }}" + item: + api_path: TicketTemplate + sub_path: "{{ tickettemplates_id }}/TicketTemplateHiddenField" + body: + num: "{{ sub_item.num | int }}" + tickettemplates_id: "{{ tickettemplates_id | int }}" + + +- name: Clear temp vars + ansible.builtin.set_fact: + template_item: {} + no_log: true diff --git a/tasks/configure.yaml b/tasks/configure.yaml new file mode 100644 index 0000000..e72f601 --- /dev/null +++ b/tasks/configure.yaml @@ -0,0 +1,111 @@ +--- +- name: Clear Any downloaded files + ansible.builtin.file: + name: "/tmp/ansible" + state: absent + #loop: "{{ glpi_plugins }}" + +- name: Clear Any downloaded files + ansible.builtin.file: + name: "/tmp/ansible" + state: directory + #loop: "{{ glpi_plugins }}" + +# - name: Download Plugins +# ansible.builtin.get_url: +# url: "{{ item.url }}" +# dest: "/tmp/{{ item.filename }}" +# loop: "{{ glpi_plugins }}" + +# - name: Download plugins +# ansible.builtin.command: +# cmd: "bash -c echo $({{ item.url }})" +# loop: "{{ glpi_plugins }}" + +# wget https://github.com/pluginsGLPI/formcreator/releases/download/2.13.6/glpi-formcreator-2.13.6.tar.bz2 -O /tmp/plugin-form-creator.tar.bz2 +# tar -xjf /tmp/plugin-form-creator.tar.bz2 -C /var/lib/docker/volumes/glpi_glpi_plugins/_data/ + +# wget https://github.com/glpi-project/glpi-inventory-plugin/releases/download/1.2.3/glpi-glpiinventory-1.2.3.tar.bz2 -O /tmp/glpi-glpiinventory-1.2.3.tar.bz2 +# tar -xjf /tmp/glpi-glpiinventory-1.2.3.tar.bz2 -C /var/lib/docker/volumes/glpi_glpi_plugins/_data/ +# chown www-data:www-data -R /var/lib/docker/volumes/glpi_glpi_plugins/_data/ + +- name: Install bzip + ansible.builtin.apt: + name: "{{ item }}" + state: present + loop: "{{ apps }}" + vars: + apps: + - bzip2 + - jq + - wget + + +# - name: Example clone of a single branch +# ansible.builtin.git: +# repo: "{{ item.repo }}.git" +# dest: "/var/lib/docker/volumes/plugins_glpi/_data/{{ item.name }}" +# single_branch: true +# version: "{{ item.version }}" +# depth: 1 +# force: true +# loop: "{{ plugins }}" +# vars: +# plugins: +# - name: actualtime +# repo: https://github.com/ticgal/actualtime +# version: 2.1.0 + +# - name: glpiinventory +# repo: https://github.com/glpi-project/glpi-inventory-plugin +# version: 1.2.3 +# # for creator doesnt work +# # - name: formcreator +# # repo: https://github.com/pluginsGLPI/formcreator +# # version: 2.13.6 + +# - name: geninventorynumber +# repo: https://github.com/pluginsGLPI/geninventorynumber +# version: 2.8.3 + +# - name: releases +# repo: https://github.com/InfotelGLPI/releases +# version: 2.0.3 + +# - name: phpsaml +# repo: https://github.com/DonutsNL/phpsaml +# # version: e7357a49ca9f0b612bc28879a0c703cdbfc4463b +# version: master + +# - name: Download and Extract the plugins +# ansible.builtin.shell: +# cmd: | +# export URL=$(curl -s {{ item.url }} | jq .assets[0].browser_download_url | tr -d \"); +# wget $URL -O /tmp/ansible/$(basename ${URL}); +# tar -xjf /tmp/ansible/$(basename ${URL}) -C /var/lib/docker/volumes/plugins_glpi/_data/; +# loop: "{{ glpi_plugins }}" +# changed_when: false + + +- name: Fix file perms + ansible.builtin.command: + cmd: chown www-data:www-data -R /var/lib/docker/volumes/plugins_glpi/_data/ + changed_when: false + +# - name: Unarchive a file that needs to be downloaded (added in 2.0) +# ansible.builtin.unarchive: +# src: /tmp/{{ item.filename }} +# dest: /var/lib/docker/volumes/plugins_glpi/_data/ +# remote_src: true +# extra_opts: +# - -j +# loop: "{{ glpi_plugins }}" + +- name: Clear Any downloaded files + ansible.builtin.file: + name: "{{ item.filename }}" + state: absent + loop: "{{ glpi_plugins }}" + +- name: Reload logroate if required + ansible.builtin.meta: flush_handlers diff --git a/tasks/install.yaml b/tasks/install.yaml new file mode 100644 index 0000000..c9df8c6 --- /dev/null +++ b/tasks/install.yaml @@ -0,0 +1,150 @@ +--- +- name: GPLI Docker Container + ansible.builtin.include_role: + name: docker_management + vars: + docker_images: + - name: "{{ docker_image_name_glpi }}" + tag: "{{ docker_image_tag_glpi }}" + + docker_networks: + - name: "{{ docker_container_name_glpi }}-access" + internal: false # this needs to be added to the docker role + - name: "{{ docker_container_name_glpi }}-smtp-access" + internal: true + + docker_containers: + - name: "{{ docker_container_name_glpi }}" + image: "{{ docker_image_name_glpi }}:{{ docker_image_tag_glpi }}" + env: + TIMEZONE: UTC + networks: + - name: "{{ docker_container_name_glpi }}-access" + - name: "ingress-access" + - name: "{{ docker_container_name_glpi }}-smtp-access" + - name: ldap-access + - name: mysql-access + # published_ports: + # - 80:80 + volumes: + - /usr/share/zoneinfo/Etc/UTC:/etc/timezone:ro + - /usr/share/zoneinfo/Etc/UTC:/etc/localtime:ro + - "config_{{ docker_container_name_glpi }}:/var/www/html/config" + - "data_{{ docker_container_name_glpi }}:/var/www/html/files" + - "log_{{ docker_container_name_glpi }}:/var/log" + - "marketplace_{{ docker_container_name_glpi }}:/var/www/html/marketplace" + - "plugins_{{ docker_container_name_glpi }}:/var/www/html/plugins" + + docker_volumes: + - name: "plugins_{{ docker_container_name_glpi }}" + - name: "data_{{ docker_container_name_glpi }}" + - name: "config_{{ docker_container_name_glpi }}" + - name: "marketplace_{{ docker_container_name_glpi }}" + - name: "log_{{ docker_container_name_glpi }}" + - name: "varlog_{{ docker_container_name_glpi }}" + + +- name: Create GLPI database + community.mysql.mysql_db: + name: "{{ mysql_database_glpi }}" + state: present + login_unix_socket: "{{ mysql_unix_socket }}" + login_user: "{{ mysql_login_user }}" + login_password: "{{ mysql_login_password }}" + login_host: "{{ mysql_login_host | default('') }}" + config_file: '' + + +- name: Create user with password, all database privileges and 'WITH GRANT OPTION' in db1 and db2 + community.mysql.mysql_user: + state: "{{ item.state | default('present') }}" + name: "{{ item.name }}" + password: "{{ item.password }}" + host: "{{ item.host | default('localhost') }}" + priv: "{{ item.priv | default(omit) | from_yaml }}" + update_password: "{{ item.update_password | default('on_create') }}" + login_host: "{{ mysql_login_host | default('') }}" + login_unix_socket: "{{ mysql_unix_socket }}" + login_user: "{{ mysql_login_user }}" + login_password: "{{ mysql_login_password }}" + config_file: '' + loop: "{{ database_mysql_users }}" + vars: + database_mysql_users: + - name: glpi + password: admin + host: '%' + priv: + 'glpi.*': 'ALL,GRANT' + +# sudo cp -r /var/www/html/glpi/config/* /var/lib/docker/volumes/glpi_config_glpi/_data/ +# sudo cp -r /var/www/html/glpi/files/* /var/lib/docker/volumes/glpi_data_glpi/_data/ +# sudo cp -r /var/www/html/glpi/plugins/* /var/lib/docker/volumes/glpi_glpi_plugins/_data/ +# sudo cp -r /var/www/html/glpi/marketplace/* /var/lib/docker/volumes/glpi_marketplace_glpi/_data/ + + +# sudo chmod -R 777 /var/lib/docker/volumes/glpi_config_glpi/_data/ +# sudo chmod -R 777 /var/lib/docker/volumes/glpi_data_glpi/_data/ +# sudo chmod -R 777 /var/lib/docker/volumes/glpi_glpi_plugins/_data/ +# sudo chmod -R 777 /var/lib/docker/volumes/glpi_marketplace_glpi/_data/ + +- name: Add fail2ban filters + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: '760' + owner: root + group: root + loop: "{{ the_files }}" + # notify: reload_fail2ban + when: > + install_fail2ban | default(false) | bool + vars: + the_files: + - src: fail2ban.filter.conf + dest: "/etc/fail2ban/filter.d/glpi.local" + - src: fail2ban.filter.conf + dest: "/etc/fail2ban/filter.d/glpi-api.local" + + +- name: "Fail2Ban Jail for GLPI" + ansible.builtin.include_role: + name: nfc_firewall + when: > + install_fail2ban | default(false) | bool + vars: + fail2ban: + config: + - name: "glpi-{{ docker_container_name_glpi }}" + sub_path: jail.d + sections: + DEFAULT: + "glpi_log": "/var/lib/docker/volumes/data_{{ docker_container_name_glpi }}/_data/_log/event.log" + glpi: + enabled: true + mode: polling + chain: DOCKER-USER + port: http,https + logpath: "%(glpi_log)s" + filter: glpi + findtime: 600 + maxretry: 5 + - name: "api_glpi-{{ docker_container_name_glpi }}" + sub_path: jail.d + sections: + DEFAULT: + "api_glpi_log": "/var/lib/docker/volumes/log_{{ docker_container_name_glpi }}/_data/apache2/access-glpi.log" + api_glpi: + enabled: true + mode: polling + chain: DOCKER-USER + port: http,https + logpath: "%(api_glpi_log)s" + filter: glpi-api + findtime: 600 + maxretry: 5 + + +- name: Task Final playbook variables + ansible.builtin.set_fact: + glpi_installed: true diff --git a/tasks/main.yaml b/tasks/main.yaml new file mode 100644 index 0000000..6461bab --- /dev/null +++ b/tasks/main.yaml @@ -0,0 +1,40 @@ +--- +- name: Install GLPI + ansible.builtin.include_tasks: + file: install.yaml + apply: + tags: + - always + tags: + - always + when: > + install_glpi | bool + and + not glpi_installed | bool + + +- name: Configure Log Rotate + ansible.builtin.include_tasks: + file: configure.yaml + apply: + tags: + - always + tags: + - always + when: glpi_installed | bool +# and +# ansible_os_family == "Debian" +# and +# ( +# logrotate is defined +# and +# logrotate | default([]) | length | int > 0 +# ) + +- name: API tasks + ansible.builtin.include_tasks: + file: api/api.yaml + apply: + tags: + - always + when: glpi_config_as_code_json | length | int > 0 diff --git a/templates/fail2ban.filter-api.conf b/templates/fail2ban.filter-api.conf new file mode 100644 index 0000000..4224099 --- /dev/null +++ b/templates/fail2ban.filter-api.conf @@ -0,0 +1,15 @@ +# +# Fail2ban Filter, GLPI API Denied access +# +# Managed By: Ansible +# Role: nfc_glpi +# +# Do not edit this file directly as it will be automagically updated by ansible. +# to make changes update the ansible play that deploys this file. +[Init] +maxlines = 2 + +[Definition] + +failregex = ^([\d|\.?]{1,3}).+apirest.php.+"\s40\d\s\d{1,5} + diff --git a/templates/fail2ban.filter.conf b/templates/fail2ban.filter.conf new file mode 100644 index 0000000..faf7b68 --- /dev/null +++ b/templates/fail2ban.filter.conf @@ -0,0 +1,17 @@ +# +# Fail2ban Filter, GLPI +# +# Managed By: Ansible +# Role: nfc_glpi +# +# Do not edit this file directly as it will be automagically updated by ansible. +# to make changes update the ansible play that deploys this file. +[Init] +maxlines = 2 + +[Definition] +# failregex = ^(?P\d{4}-\d{2}-\d{2}\s?\d{2}:\d{2}:\d{2})\s+?\S+\n?\[login\]\s+?[\d+]?:?[\s+]?Failed\s+?login\s+?for\s(?P.+)\s+?from\s+?IP\s+?(?P\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$ + +# failregex = ^(.+)ogin] \d+: Failed login for (.+) from IP (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$ +failregex = ^.*?(Failed login for)[\S\s]+(from IP) .*$ +# ^.*\s(\[\S).*?(Failed login for) \S+ (from IP) .*$ diff --git a/website-template b/website-template new file mode 160000 index 0000000..992b548 --- /dev/null +++ b/website-template @@ -0,0 +1 @@ +Subproject commit 992b54805b8b6c78a3d2a5ea7de71c7be2b070c8