From 4ef7814e40625268b1eb10e30a5e26ed23b2e29f Mon Sep 17 00:00:00 2001 From: Alexandre Rodrigues Date: Tue, 2 Apr 2024 18:02:25 +0200 Subject: [PATCH 1/7] Support configuring feature_toggles in grafana role --- roles/grafana/README.md | 1 + roles/grafana/defaults/main.yml | 6 ++++++ roles/grafana/templates/grafana.ini.j2 | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/roles/grafana/README.md b/roles/grafana/README.md index eb00b3f2..7c4da8f2 100644 --- a/roles/grafana/README.md +++ b/roles/grafana/README.md @@ -57,6 +57,7 @@ All variables which can be overridden are stored in [defaults/main.yml](defaults | `grafana_snapshots` | {} | [snapshots](http://docs.grafana.org/installation/configuration/#snapshots) configuration section | | `grafana_image_storage` | {} | [image storage](http://docs.grafana.org/installation/configuration/#external-image-storage) configuration section | | `grafana_date_formats` | {} | [date formats](http://docs.grafana.org/installation/configuration/#date_formats) configuration section | +| `grafana_feature_toggles` | {} | [feature toggles](http://docs.grafana.org/installation/configuration/#feature_toggles) configuration section | | `grafana_dashboards` | [] | List of dashboards which should be imported | | `grafana_dashboards_dir` | "dashboards" | Path to a local directory containing dashboards files in `json` format | | `grafana_datasources` | [] | List of datasources which should be configured | diff --git a/roles/grafana/defaults/main.yml b/roles/grafana/defaults/main.yml index 12f3d7cc..e2f6a547 100644 --- a/roles/grafana/defaults/main.yml +++ b/roles/grafana/defaults/main.yml @@ -212,6 +212,12 @@ grafana_date_formats: {} # use_browser_locale: true # default_timezone: "browser" +# Feature toggles +# List of feature toggles: https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/feature-toggles/#feature-toggles +grafana_feature_toggles: {} +# autoMigrateOldPanels: true +# regressionTransformation: true + ####### # Plugins from https://grafana.com/plugins grafana_plugins: [] diff --git a/roles/grafana/templates/grafana.ini.j2 b/roles/grafana/templates/grafana.ini.j2 index df6eab14..e37c4f88 100644 --- a/roles/grafana/templates/grafana.ini.j2 +++ b/roles/grafana/templates/grafana.ini.j2 @@ -212,3 +212,11 @@ provider = {{ grafana_image_storage.provider }} {{ k }} = {{ v }} {% endfor %} {% endif %} + +# Feature toggles +{% if grafana_feature_toggles != {} %} +[feature_toggles] +{% for k,v in grafana_feature_toggles.items() %} +{{ k }} = {{ v }} +{% endfor %} +{% endif %} \ No newline at end of file From efa539dde74bf0e74a1c248e2e6a27dbc0c8f4aa Mon Sep 17 00:00:00 2001 From: Alexandre Rodrigues Date: Tue, 16 Apr 2024 22:13:13 +0200 Subject: [PATCH 2/7] Add newline at the end of file --- roles/grafana/templates/grafana.ini.j2 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/roles/grafana/templates/grafana.ini.j2 b/roles/grafana/templates/grafana.ini.j2 index e37c4f88..11190b0a 100644 --- a/roles/grafana/templates/grafana.ini.j2 +++ b/roles/grafana/templates/grafana.ini.j2 @@ -219,4 +219,5 @@ provider = {{ grafana_image_storage.provider }} {% for k,v in grafana_feature_toggles.items() %} {{ k }} = {{ v }} {% endfor %} -{% endif %} \ No newline at end of file +{% endif %} + From bd674dc256211e1aaca416b4fd3680f0b043e638 Mon Sep 17 00:00:00 2001 From: Alexandre Rodrigues Date: Tue, 16 Apr 2024 23:26:01 +0200 Subject: [PATCH 3/7] Move feature_toggles comment inside condition block --- roles/grafana/templates/grafana.ini.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/grafana/templates/grafana.ini.j2 b/roles/grafana/templates/grafana.ini.j2 index 11190b0a..0672ffaa 100644 --- a/roles/grafana/templates/grafana.ini.j2 +++ b/roles/grafana/templates/grafana.ini.j2 @@ -213,8 +213,8 @@ provider = {{ grafana_image_storage.provider }} {% endfor %} {% endif %} -# Feature toggles {% if grafana_feature_toggles != {} %} +# Feature toggles [feature_toggles] {% for k,v in grafana_feature_toggles.items() %} {{ k }} = {{ v }} From 70211a000368a1935b8e32b55291f9eaee8dfa2a Mon Sep 17 00:00:00 2001 From: VoidQuark <115592832+voidquark@users.noreply.github.com> Date: Mon, 13 May 2024 09:21:31 +0200 Subject: [PATCH 4/7] feat: add promtail role (#197) Co-authored-by: Ishan Jain <51803183+ishanjainn@users.noreply.github.com> --- .github/workflows/promtail-molecule.yml | 44 +++++ CODEOWNERS | 1 + README.md | 6 +- examples/promtail-multiple-logs.yml | 24 +++ roles/promtail/README.md | 164 +++++++++++++++++++ roles/promtail/defaults/main.yml | 47 ++++++ roles/promtail/handlers/main.yml | 9 + roles/promtail/meta/main.yml | 28 ++++ roles/promtail/molecule/default/converge.yml | 15 ++ roles/promtail/molecule/default/molecule.yml | 20 +++ roles/promtail/tasks/acl_configuration.yml | 116 +++++++++++++ roles/promtail/tasks/deploy.yml | 139 ++++++++++++++++ roles/promtail/tasks/main.yml | 23 +++ roles/promtail/tasks/setup-Debian.yml | 14 ++ roles/promtail/tasks/setup-RedHat.yml | 9 + roles/promtail/tasks/uninstall.yml | 119 ++++++++++++++ roles/promtail/templates/config.yml.j2 | 22 +++ roles/promtail/templates/promtail.service.j2 | 18 ++ roles/promtail/templates/promtail_acl.j2 | 13 ++ roles/promtail/vars/Debian.yml | 5 + roles/promtail/vars/RedHat.yml | 2 + 21 files changed, 836 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/promtail-molecule.yml create mode 100644 examples/promtail-multiple-logs.yml create mode 100644 roles/promtail/README.md create mode 100644 roles/promtail/defaults/main.yml create mode 100644 roles/promtail/handlers/main.yml create mode 100644 roles/promtail/meta/main.yml create mode 100644 roles/promtail/molecule/default/converge.yml create mode 100644 roles/promtail/molecule/default/molecule.yml create mode 100644 roles/promtail/tasks/acl_configuration.yml create mode 100644 roles/promtail/tasks/deploy.yml create mode 100644 roles/promtail/tasks/main.yml create mode 100644 roles/promtail/tasks/setup-Debian.yml create mode 100644 roles/promtail/tasks/setup-RedHat.yml create mode 100644 roles/promtail/tasks/uninstall.yml create mode 100644 roles/promtail/templates/config.yml.j2 create mode 100644 roles/promtail/templates/promtail.service.j2 create mode 100644 roles/promtail/templates/promtail_acl.j2 create mode 100644 roles/promtail/vars/Debian.yml create mode 100644 roles/promtail/vars/RedHat.yml diff --git a/.github/workflows/promtail-molecule.yml b/.github/workflows/promtail-molecule.yml new file mode 100644 index 00000000..e8168b45 --- /dev/null +++ b/.github/workflows/promtail-molecule.yml @@ -0,0 +1,44 @@ +--- +name: Promtail Molecule + +on: + push: + branches: + - main + pull_request: + branches: + - main + +defaults: + run: + working-directory: roles/promtail + +jobs: + molecule: + name: Molecule + runs-on: ubuntu-latest + strategy: + matrix: + distro: + - rockylinux9 + - ubuntu2204 + - debian12 + + steps: + - name: Check out the codebase. + uses: actions/checkout@v4 + + - name: Set up Python 3. + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Install test dependencies. + run: pip3 install ansible molecule molecule-plugins[docker] docker + + - name: Run Molecule tests. + run: molecule test + env: + PY_COLORS: '1' + ANSIBLE_FORCE_COLOR: '1' + MOLECULE_DISTRO: ${{ matrix.distro }} diff --git a/CODEOWNERS b/CODEOWNERS index 0be0ae86..9be7737a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,3 +5,4 @@ /roles/opentelemetry_collector @ishanjainn /roles/loki @voidquark @ishanjainn /roles/mimir @GVengelen @gardar @ishanjainn +/roles/promtail @voidquark @ishanjainn diff --git a/README.md b/README.md index 8b0df350..ceef02c7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![GitHub Last Commit](https://img.shields.io/github/last-commit/grafana/grafana-ansible-collection)](https://github.com/grafana/grafana-ansible-collection/tags) [![GitHub Contributors](https://img.shields.io/github/contributors/grafana/grafana-ansible-collection)](https://github.com/grafana/grafana-ansible-collection/tags) -This collection (`grafana.grafana`) contains modules and roles to assist in automating the management of resources in **Grafana**, **Grafana Agent**, **OpenTelemetry Collector**, and **Loki** with Ansible. +This collection (`grafana.grafana`) contains modules and roles to assist in automating the management of resources in **Grafana**, **Grafana Agent**, **OpenTelemetry Collector**, **Loki**, **Mimir**, and **Promtail** with Ansible. - [Ansible collection Documentation](https://docs.ansible.com/ansible/latest/collections/grafana/grafana/) - [Grafana](https://grafana.com) @@ -43,12 +43,14 @@ collections: ## Roles included in the collection -This collection includes the following roles to help set up and manage Grafana, Grafana Agent, OpenTelemetry Collector, and Loki: +This collection includes the following roles to help set up and manage Grafana, Grafana Agent, OpenTelemetry Collector, Loki, Mimir and Promtail: - **Grafana**: Installs and configures Grafana on your target hosts. - **Grafana Agent**: Deploys and configures Grafana Agent, allowing for efficient metrics, logs, and trace data shipping to Grafana Cloud or other endpoints. - **OpenTelemetry Collector**: Sets up and configures the OpenTelemetry Collector, enabling advanced observability features through data collection and transmission. - **Loki**: Deploy and manage Loki, the log aggregation system. +- **Mimir**: Deploy and manage Mimir, the scalable long-term storage for Prometheus. +- **Promtail**: Deploy and manage Promtail, the agent which ships the contents of local logs to a private Grafana Loki. ## Using this collection diff --git a/examples/promtail-multiple-logs.yml b/examples/promtail-multiple-logs.yml new file mode 100644 index 00000000..d49f542a --- /dev/null +++ b/examples/promtail-multiple-logs.yml @@ -0,0 +1,24 @@ +--- +- name: Deploy Promtail to ship logs to the local Loki instance + hosts: all + become: true + roles: + - role: grafana.grafana.promtail + vars: + promtail_clients: + - url: http://localhost:3100/loki/api/v1/push + promtail_scrape_configs: + - job_name: system + static_configs: + - targets: + - localhost + labels: + job: messages + instance: "{{ ansible_fqdn }}" + __path__: /var/log/messages + - targets: + - localhost + labels: + job: nginx + instance: "{{ ansible_fqdn }}" + __path__: /var/log/nginx/*.log diff --git a/roles/promtail/README.md b/roles/promtail/README.md new file mode 100644 index 00000000..1fbcb550 --- /dev/null +++ b/roles/promtail/README.md @@ -0,0 +1,164 @@ +# Ansible role - Promtail + +[![License](https://img.shields.io/github/license/grafana/grafana-ansible-collection)](LICENSE) + +The Ansible Promtail Role allows you to effortlessly deploy and manage Promtail, agent which ships contents of local logs to private Loki. +This role is tailored for operating systems such as **RedHat**, **Rocky Linux**, **AlmaLinux**, **Ubuntu**, and **Debian**. + +**๐Ÿ”‘ Key Features** +- **โšก Root-less/Root runtime**: By default, Promtail operates in root-less mode, utilizing ACL (Access Control List) to securely access logs without requiring root permissions. You have the option to configure root mode if necessary. +- **๐Ÿงน Effortless Uninstall**: Easily remove Promtail from your system using the "promtail_uninstall" tag. + +๐Ÿ“ข **[Check the blog post](https://voidquark.com/blog/rootless-promtail-with-ansible/)** ๐Ÿ“ **Learn more about root-less mode.** + +## Table of Content + +- [Requirements](#requirements) +- [Role Variables](#role-variables) +- [Playbook](#playbook) + +## Requirements + +- Ansible 2.10+ + +## Role Variables + +```yaml +promtail_version: "latest" +``` +The version of Promtail to download and deploy. Supported standard version "3.0.0" format or "latest". + +```yaml +promtail_http_listen_port: 9080 +``` +The TCP port on which Promtail listens. By default, it listens on port `9080`. + +```yaml +promtail_http_listen_address: "0.0.0.0" +``` +The address on which Promtail listens for HTTP requests. By default, it listens on all interfaces. + +```yaml +promtail_expose_port: false +``` +By default, this is set to `false`. It supports only simple `firewalld` configurations. If set to `true`, a firewalld rule is added to expose the TCP `promtail_http_listen_port`. If set to `false`, configuration is skipped. If the `firewalld.service` is not active, all firewalld tasks are skipped. + +```yaml +promtail_positions_path: "/var/lib/promtail" +``` +Promtail path for position file. File indicating how far it has read into a file. It is needed for when Promtail is restarted to allow it to continue from where it left off. + +```yaml +promtail_runtime_mode: "acl" +``` +By default, Promtail runs in root-less mode. It supports two modes: +- `acl`: Root-less mode, utilizing ACL permission model to read target log files. +- `root`: Root mode, where Promtail runs as root and ACL configuration is skipped. + +```yaml +promtail_user_append_groups: + - "systemd-journal" +``` +Appends the promtail user to specific groups in root-less mode. By default, it appends the user to the `systemd-journal` group, granting permission to read system journal logs. + +```yaml +promtail_download_url_rpm: "https://github.com/grafana/loki/releases/download/v{{ promtail_version }}/promtail-{{ promtail_version }}.{{ __promtail_arch }}.rpm" +``` +The default download URL for the Promtail rpm package from GitHub. + +```yaml +promtail_download_url_deb: "https://github.com/grafana/loki/releases/download/v{{ promtail_version }}/promtail_{{ promtail_version }}_{{ __promtail_arch }}.deb" +``` +The default download URL for the Promtail deb package from GitHub. + +```yaml +promtail_server: + http_listen_port: "{{ promtail_http_listen_port }}" + http_listen_address: "{{ promtail_http_listen_address }}" +``` +The `server` block configures Promtail behavior as an HTTP server. [All possible values for `server`](https://grafana.com/docs/loki/latest/clients/promtail/configuration/#server) + +```yaml +promtail_positions: + filename: "{{ promtail_positions_path }}/positions.yaml" +``` +The `positions` block configures where Promtail will save a file indicating how far it has read into a file. It is needed for when Promtail is restarted to allow it to continue from where it left off. [All possible values for `positions`](https://grafana.com/docs/loki/latest/clients/promtail/configuration/#positions) + +```yaml +promtail_clients: + - url: http://localhost:3100/loki/api/v1/push +``` +The `clients` block configures how Promtail connects to instances of Loki. [All possible values for `clients`](https://grafana.com/docs/loki/latest/clients/promtail/configuration/#clients). โš ๏ธ This configuration is mandatory. By default, it's empty, and the example above serves as a simple illustration for inspiration. + +```yaml +promtail_scrape_configs: + - job_name: system + static_configs: + - targets: + - localhost + labels: + job: messages + instance: "{{ ansible_fqdn }}" + __path__: /var/log/messages + - targets: + - localhost + labels: + job: nginx + instance: "{{ ansible_fqdn }}" + __path__: /var/log/nginx/*.log +``` +The `scrape_configs` block configures how Promtail can scrape logs from a series of targets using a specified discovery method. [All possible values for `scrape_configs`](https://grafana.com/docs/loki/latest/clients/promtail/configuration/#scrape_configs). โš ๏ธ This configuration is mandatory. By default, it's empty, and the example above serves as a simple illustration for inspiration. + +| Variable Name | Description +| ----------- | ----------- | +| `promtail_limits_config` | The optional limits_config block configures global limits for this instance of Promtail. ๐Ÿ“š [documentation](https://grafana.com/docs/loki/latest/clients/promtail/configuration/#limits_config). +| `promtail_target_config` | The target_config block controls the behavior of reading files from discovered targets. ๐Ÿ“š [documentation](https://grafana.com/docs/loki/latest/clients/promtail/configuration/#target_config). + +## Dependencies + +No Dependencies + +## Playbook + +```yaml +- name: Manage promtail service + hosts: all + become: true + vars: + promtail_clients: + - url: http://localhost:3100/loki/api/v1/push + promtail_scrape_configs: + - job_name: system + static_configs: + - targets: + - localhost + labels: + job: messages + instance: "{{ ansible_fqdn }}" + __path__: /var/log/messages + - targets: + - localhost + labels: + job: nginx + instance: "{{ ansible_fqdn }}" + __path__: /var/log/nginx/*.log + roles: + - role: grafana.grafana.promtail +``` + +- Playbook execution example +```shell +# Deploy Promtail +ansible-playbook function_promtail_play.yml + +# Uninstall Promtail +ansible-playbook function_promtail_play.yml -t promtail_uninstall +``` + +## License + +See [LICENSE](https://github.com/grafana/grafana-ansible-collection/blob/main/LICENSE) + +## Author Information + +- [VoidQuark](https://github.com/voidquark) diff --git a/roles/promtail/defaults/main.yml b/roles/promtail/defaults/main.yml new file mode 100644 index 00000000..277037bf --- /dev/null +++ b/roles/promtail/defaults/main.yml @@ -0,0 +1,47 @@ +--- +# defaults file for promtail +promtail_version: "latest" +promtail_http_listen_port: 9080 +promtail_http_listen_address: "0.0.0.0" +promtail_expose_port: false +promtail_positions_path: "/var/lib/promtail" +promtail_runtime_mode: "acl" # Supported "root" or "acl" + +promtail_user_append_groups: + - "systemd-journal" + +promtail_download_url_rpm: "https://github.com/grafana/loki/releases/download/v{{ promtail_version }}/promtail-{{ promtail_version }}.{{ __promtail_arch }}.rpm" +promtail_download_url_deb: "https://github.com/grafana/loki/releases/download/v{{ promtail_version }}/promtail_{{ promtail_version }}_{{ __promtail_arch }}.deb" + +# default variables for /etc/promtail/config.yml +promtail_server: + http_listen_port: "{{ promtail_http_listen_port }}" + http_listen_address: "{{ promtail_http_listen_address }}" + +promtail_positions: + filename: "{{ promtail_positions_path }}/positions.yaml" + +promtail_clients: [] +# promtail_clients: +# - url: http://localhost:3100/loki/api/v1/push + +promtail_scrape_configs: [] +# promtail_scrape_configs: +# - job_name: system +# static_configs: +# - targets: +# - localhost +# labels: +# job: messages +# instance: "{{ ansible_fqdn }}" +# __path__: /var/log/messages +# - targets: +# - localhost +# labels: +# job: nginx +# instance: "{{ ansible_fqdn }}" +# __path__: /var/log/nginx/*.log + +# not set by default +# promtail_limits_config: +# promtail_target_config: diff --git a/roles/promtail/handlers/main.yml b/roles/promtail/handlers/main.yml new file mode 100644 index 00000000..d9f17243 --- /dev/null +++ b/roles/promtail/handlers/main.yml @@ -0,0 +1,9 @@ +--- +# handlers file for promtail +- name: Restart promtail + listen: "restart promtail" + ansible.builtin.systemd: + daemon_reload: true + name: promtail.service + state: restarted + enabled: true diff --git a/roles/promtail/meta/main.yml b/roles/promtail/meta/main.yml new file mode 100644 index 00000000..c7cee9a2 --- /dev/null +++ b/roles/promtail/meta/main.yml @@ -0,0 +1,28 @@ +--- +galaxy_info: + role_name: promtail + author: voidquark + description: Manage Grafana Promtail Application + license: "GPL-3.0-or-later" + min_ansible_version: "2.10" + platforms: + - name: EL + versions: + - "9" + - "8" + - name: Fedora + versions: + - all + - name: Debian + versions: + - all + - name: Ubuntu + versions: + - all + galaxy_tags: + - promtail + - grafana + - logging + - monitoring + +dependencies: [] diff --git a/roles/promtail/molecule/default/converge.yml b/roles/promtail/molecule/default/converge.yml new file mode 100644 index 00000000..d9945b10 --- /dev/null +++ b/roles/promtail/molecule/default/converge.yml @@ -0,0 +1,15 @@ +--- +- name: Converge + hosts: all + vars: + promtail_scrape_configs: + - job_name: test + static_configs: + - targets: + - localhost + labels: + job: test + instance: "{{ ansible_fqdn }}" + __path__: /var/log/last* + roles: + - role: grafana.grafana.promtail diff --git a/roles/promtail/molecule/default/molecule.yml b/roles/promtail/molecule/default/molecule.yml new file mode 100644 index 00000000..339965a5 --- /dev/null +++ b/roles/promtail/molecule/default/molecule.yml @@ -0,0 +1,20 @@ +--- +dependency: + name: galaxy + options: + ignore-errors: true +driver: + name: docker +platforms: + - name: instance + image: "geerlingguy/docker-${MOLECULE_DISTRO:-rockylinux8}-ansible:latest" + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + playbooks: + converge: converge.yml diff --git a/roles/promtail/tasks/acl_configuration.yml b/roles/promtail/tasks/acl_configuration.yml new file mode 100644 index 00000000..65516b92 --- /dev/null +++ b/roles/promtail/tasks/acl_configuration.yml @@ -0,0 +1,116 @@ +--- +# tasks file for promtail deploy - acl configuration + +- name: Extract log files from static_configs - labels - path + ansible.builtin.set_fact: + __promtail_acl_log_files: >- + {{ + promtail_scrape_configs + | selectattr('static_configs', 'defined') + | map(attribute='static_configs') + | flatten + | map(attribute='labels') + | map(attribute='__path__') + | list + }} + +- name: Extract log dirs paths from static_configs - labels - path + ansible.builtin.set_fact: + __promtail_acl_log_dirs: >- + {{ + promtail_scrape_configs + | selectattr('static_configs', 'defined') + | map(attribute='static_configs') + | flatten + | map(attribute='labels') + | map(attribute='__path__') + | map('dirname') + | unique + | list + }} + +- name: Stat log dirs + ansible.builtin.stat: + path: "{{ item }}" + loop: "{{ __promtail_acl_log_dirs }}" + register: __promtail_stat_acl_log_dirs + +- name: Set recursive default ACL permission for log dirs + ansible.posix.acl: + path: "{{ item.item }}" + recursive: true + entity: promtail + etype: user + permissions: rx + default: true + state: present + loop: "{{ __promtail_stat_acl_log_dirs.results }}" + when: + - __promtail_stat_acl_log_dirs | length > 0 + - item.stat.exists + notify: restart promtail + +- name: Set ACL permission for log dirs + ansible.posix.acl: + path: "{{ item.item }}" + entity: promtail + etype: user + permissions: rx + state: present + loop: "{{ __promtail_stat_acl_log_dirs.results }}" + when: + - __promtail_stat_acl_log_dirs | length > 0 + - item.stat.exists + notify: restart promtail + +- name: Find all existing ACL log files + ansible.builtin.find: + paths: "{{ item | dirname }}" + patterns: "{{ item | basename }}" + loop: "{{ __promtail_acl_log_files }}" + register: __promtail_find_files + +- name: Define existing ACL log files + ansible.builtin.set_fact: + __promtail_existing_acl_log_files: "{{ __promtail_find_files.results | map(attribute='files') | flatten | map(attribute='path') }}" + +- name: Set ACL permission for existing log files + ansible.posix.acl: + path: "{{ item }}" + entity: promtail + etype: user + permissions: r + state: present + loop: "{{ __promtail_existing_acl_log_files }}" + when: + - __promtail_existing_acl_log_files | length > 0 + notify: restart promtail + +- name: Promtail ACL Logrotate + when: + - __promtail_acl_log_dirs | length > 0 + - __promtail_acl_log_files | length > 0 + block: + - name: Template promtail ACL config for Logrotate + ansible.builtin.template: + src: "promtail_acl.j2" + dest: "/etc/logrotate.d/promtail_acl" + owner: "root" + group: "root" + mode: "0644" + + - name: Ensure that Promtail dummy dir for logrotate ACL configuration exist + ansible.builtin.file: + path: "/var/log/dummy_promtail_acl" + state: directory + owner: "promtail" + group: "root" + mode: "0750" + + - name: Create dummy empty log file for logrotate ACL configuration to work + ansible.builtin.copy: + content: "" + dest: "/var/log/dummy_promtail_acl/dummy_promtail_acl.log" + owner: "promtail" + group: "root" + mode: 0600 diff --git a/roles/promtail/tasks/deploy.yml b/roles/promtail/tasks/deploy.yml new file mode 100644 index 00000000..483a9b1b --- /dev/null +++ b/roles/promtail/tasks/deploy.yml @@ -0,0 +1,139 @@ +--- +# tasks file for promtail deploy + +- name: Obtain the latest version from the GitHub repo + when: promtail_version == "latest" + block: + - name: Scrape Github API endpoint to obtain latest Promtail version + ansible.builtin.uri: + url: "https://api.github.com/repos/grafana/loki/releases/latest" + method: GET + body_format: json + become: false + delegate_to: localhost + run_once: true + register: __github_latest_version + + - name: Latest available Promtail version + ansible.builtin.set_fact: + promtail_version: "{{ __github_latest_version.json.tag_name | regex_replace('^v?(\\d+\\.\\d+\\.\\d+)$', '\\1') }}" + +- name: Verify current deployed version + block: + - name: Check if Promtail binary is present + ansible.builtin.stat: + path: "/usr/bin/promtail" + register: __already_deployed + + - name: Obtain current deployed Promtail version + ansible.builtin.command: + cmd: "/usr/bin/promtail --version" + changed_when: false + register: __current_deployed_version + when: __already_deployed.stat.exists | bool + +- name: Include RedHat/Rocky setup + ansible.builtin.include_tasks: + file: setup-RedHat.yml + when: ansible_os_family in ['RedHat', 'Rocky'] + +- name: Include Debian/Ubuntu setup + ansible.builtin.include_tasks: + file: setup-Debian.yml + when: ansible_os_family == 'Debian' + +- name: Ensure that Promtail position path exists + ansible.builtin.file: + path: "{{ promtail_positions_path }}" + state: directory + owner: "promtail" + group: "root" + mode: "0750" + notify: restart promtail + +- name: Template Promtail config - /etc/promtail/config.yml + ansible.builtin.template: + src: "config.yml.j2" + dest: "/etc/promtail/config.yml" + owner: "promtail" + group: "root" + mode: "0644" + validate: "/usr/bin/promtail -check-syntax -config.file %s" + notify: restart promtail + +- name: Template Promtail systemd - /etc/systemd/system/promtail.service + ansible.builtin.template: + src: "promtail.service.j2" + dest: "/etc/systemd/system/promtail.service" + owner: "root" + group: "root" + mode: "0644" + notify: restart promtail + +- name: Add the Promtail system user to additional group + ansible.builtin.user: + name: "promtail" + groups: "{{ item }}" + system: true + append: true + create_home: false + state: present + loop: "{{ promtail_user_append_groups }}" + when: + - promtail_user_append_groups | length > 0 + - promtail_runtime_mode == "acl" + +- name: Include Promtail ACL permission configuration + ansible.builtin.include_tasks: + file: "acl_configuration.yml" + when: + - promtail_scrape_configs | length > 0 + - promtail_runtime_mode == "acl" + +- name: Get firewalld state + ansible.builtin.systemd: + name: "firewalld" + register: __firewalld_service_state + +- name: Enable firewalld rule to expose Promtail tcp port {{ promtail_http_listen_port }} + ansible.posix.firewalld: + immediate: true + permanent: true + port: "{{ promtail_http_listen_port }}/tcp" + state: enabled + when: + - __firewalld_service_state.status.ActiveState == "active" + - promtail_expose_port | bool + +- name: Flush handlers after deployment + ansible.builtin.meta: flush_handlers + +- name: Ensure that Promtail is started + ansible.builtin.systemd: + name: promtail.service + state: started + +- name: Stat position file + ansible.builtin.stat: + path: "{{ promtail_positions_path }}/positions.yaml" + register: __promtail_stat_position_file + +- name: Ensure correct owner and group for Promtail position file + ansible.builtin.file: + path: "{{ promtail_positions_path }}/positions.yaml" + state: file + owner: "promtail" + notify: restart promtail + when: + - __promtail_stat_position_file.stat.exists + - promtail_runtime_mode == "acl" + +- name: Verify that Promtail URL is responding + ansible.builtin.uri: + url: "http://{{ promtail_http_listen_address }}:{{ promtail_http_listen_port }}/ready" + method: GET + register: promtail_verify_url_status_code + retries: 5 + delay: 8 + until: promtail_verify_url_status_code.status == 200 + when: promtail_expose_port | bool diff --git a/roles/promtail/tasks/main.yml b/roles/promtail/tasks/main.yml new file mode 100644 index 00000000..11bfdbf1 --- /dev/null +++ b/roles/promtail/tasks/main.yml @@ -0,0 +1,23 @@ +--- +# tasks file for promtail +- name: Include OS specific variables + ansible.builtin.include_vars: + file: "{{ ansible_os_family }}.yml" + +- name: Deploy Promtail service + ansible.builtin.include_tasks: + file: "deploy.yml" + apply: + tags: promtail_deploy + tags: promtail_deploy + +- name: Uninstall Promtail service + ansible.builtin.include_tasks: + file: "uninstall.yml" + apply: + tags: + - promtail_uninstall + - never + tags: + - promtail_uninstall + - never diff --git a/roles/promtail/tasks/setup-Debian.yml b/roles/promtail/tasks/setup-Debian.yml new file mode 100644 index 00000000..3192279e --- /dev/null +++ b/roles/promtail/tasks/setup-Debian.yml @@ -0,0 +1,14 @@ +--- +- name: APT - Ensure that ACL is present + ansible.builtin.apt: + name: "acl" + state: present + update_cache: yes + when: promtail_runtime_mode == "acl" + +- name: APT - Install Promtail + ansible.builtin.apt: + deb: "{{ promtail_download_url_deb }}" + state: present + notify: restart promtail + when: __current_deployed_version.stdout is not defined or promtail_version not in __current_deployed_version.stdout diff --git a/roles/promtail/tasks/setup-RedHat.yml b/roles/promtail/tasks/setup-RedHat.yml new file mode 100644 index 00000000..b50573da --- /dev/null +++ b/roles/promtail/tasks/setup-RedHat.yml @@ -0,0 +1,9 @@ +--- +- name: DNF - Install Promtail from remote URL + ansible.builtin.dnf: + name: "{{ promtail_download_url_rpm }}" + state: present + disable_gpg_check: true + notify: restart promtail + when: + - __current_deployed_version.stdout is not defined or promtail_version not in __current_deployed_version.stdout diff --git a/roles/promtail/tasks/uninstall.yml b/roles/promtail/tasks/uninstall.yml new file mode 100644 index 00000000..0cac84d8 --- /dev/null +++ b/roles/promtail/tasks/uninstall.yml @@ -0,0 +1,119 @@ +--- +# tasks file for promtail uninstall +- name: Stop Promtail service + ansible.builtin.systemd: # noqa ignore-errors + name: promtail + state: stopped + ignore_errors: true + +- name: Extract log files from static_configs - labels - path + ansible.builtin.set_fact: + __promtail_acl_log_files: >- + {{ + promtail_scrape_configs + | selectattr('static_configs', 'defined') + | map(attribute='static_configs') + | flatten + | map(attribute='labels') + | map(attribute='__path__') + | list + }} + +- name: Extract log dirs paths from static_configs - labels - path + ansible.builtin.set_fact: + __promtail_acl_log_dirs: >- + {{ + promtail_scrape_configs + | selectattr('static_configs', 'defined') + | map(attribute='static_configs') + | flatten + | map(attribute='labels') + | map(attribute='__path__') + | map('dirname') + | list + }} + +- name: Remove ACL Permission for log dirs - default + ansible.posix.acl: # noqa ignore-errors + path: "{{ item }}" + recursive: true + entity: promtail + etype: user + default: true + state: absent + loop: "{{ __promtail_acl_log_dirs }}" + ignore_errors: true + +- name: Remove ACL permission for log dirs + ansible.posix.acl: # noqa ignore-errors + path: "{{ item }}" + entity: promtail + etype: user + state: absent + loop: "{{ __promtail_acl_log_dirs }}" + ignore_errors: true + +- name: Find all existing ACL log files + ansible.builtin.find: + paths: "{{ item | dirname }}" + patterns: "{{ item | basename }}" + loop: "{{ __promtail_acl_log_files }}" + register: __promtail_find_files + +- name: Define existing ACL log files + ansible.builtin.set_fact: + __promtail_existing_acl_log_files: "{{ __promtail_find_files.results | map(attribute='files') | flatten | map(attribute='path') }}" + +- name: Remove ACL Permission for existing log files + ansible.posix.acl: # noqa ignore-errors + path: "{{ item }}" + entity: promtail + etype: user + state: absent + loop: "{{ __promtail_existing_acl_log_files }}" + ignore_errors: true + +- name: Uninstall Promtail rpm package + ansible.builtin.dnf: + name: "promtail" + state: absent + autoremove: true + when: ansible_os_family in ['RedHat', 'Rocky'] + +- name: Uninstall Promtail deb package + ansible.builtin.apt: + name: "promtail" + state: absent + purge: true + when: ansible_os_family == 'Debian' + +- name: Ensure that Promtail firewalld rule is not present - tcp port {{ promtail_http_listen_port }} + ansible.posix.firewalld: # noqa ignore-errors + immediate: true + permanent: true + port: "{{ promtail_http_listen_port }}/tcp" + state: disabled + ignore_errors: true + +- name: Remove Promtail directories" + ansible.builtin.file: + path: "{{ remove_me }}" + state: absent + loop: + - "/etc/promtail" + - "{{ promtail_positions_path }}" + - "/etc/logrotate.d/promtail_acl" + - "/var/log/dummy_promtail_acl" + loop_control: + loop_var: remove_me + +- name: Remove the Promtail system user + ansible.builtin.user: + name: "promtail" + force: true + state: absent + +- name: Remove Promtail system group + ansible.builtin.group: + name: "promtail" + state: absent diff --git a/roles/promtail/templates/config.yml.j2 b/roles/promtail/templates/config.yml.j2 new file mode 100644 index 00000000..83681310 --- /dev/null +++ b/roles/promtail/templates/config.yml.j2 @@ -0,0 +1,22 @@ +server: + {{ promtail_server | to_nice_yaml(indent=2,sort_keys=False) | indent(2, False) }} +{% if promtail_positions is defined %} +positions: + {{ promtail_positions | to_nice_yaml(indent=2,sort_keys=False) | indent(2, False) }} +{% endif %} +{% if promtail_clients is defined %} +clients: + {{ promtail_clients | to_nice_yaml(indent=2,sort_keys=False) | indent(2, False) }} +{% endif %} +{% if promtail_scrape_configs is defined %} +scrape_configs: + {{ promtail_scrape_configs | to_nice_yaml(indent=2,sort_keys=False) | indent(2, False) }} +{% endif %} +{% if promtail_limits_config is defined %} +limits_config: + {{ promtail_limits_config | to_nice_yaml(indent=2,sort_keys=False) | indent(2, False) }} +{% endif %} +{% if promtail_target_config is defined %} +target_config: + {{ promtail_target_config | to_nice_yaml(indent=2,sort_keys=False) | indent(2, False) }} +{% endif %} diff --git a/roles/promtail/templates/promtail.service.j2 b/roles/promtail/templates/promtail.service.j2 new file mode 100644 index 00000000..6dc8384d --- /dev/null +++ b/roles/promtail/templates/promtail.service.j2 @@ -0,0 +1,18 @@ +[Unit] +Description=Promtail service +After=network.target + +[Service] +Type=simple +{% if promtail_runtime_mode == "acl" %} +User=promtail +{% elif promtail_runtime_mode == "root" %} +User=root +{% endif %} +ExecStart=/usr/bin/promtail -config.file /etc/promtail/config.yml + +TimeoutSec = 60 +Restart = on-failure +RestartSec = 2 + +[Install] diff --git a/roles/promtail/templates/promtail_acl.j2 b/roles/promtail/templates/promtail_acl.j2 new file mode 100644 index 00000000..40090658 --- /dev/null +++ b/roles/promtail/templates/promtail_acl.j2 @@ -0,0 +1,13 @@ +/var/log/dummy_promtail_acl/dummy_promtail_acl.log +{ + copytruncate + postrotate +{% for each_dir in __promtail_acl_log_dirs %} + /usr/bin/setfacl -R -m d:u:promtail:rx {{ each_dir }} + /usr/bin/setfacl -m u:promtail:rx {{ each_dir }} +{% endfor %} +{% for each_log in __promtail_acl_log_files %} + /usr/bin/setfacl -m u:promtail:r {{ each_log }} +{% endfor %} + endscript +} diff --git a/roles/promtail/vars/Debian.yml b/roles/promtail/vars/Debian.yml new file mode 100644 index 00000000..f9d41b28 --- /dev/null +++ b/roles/promtail/vars/Debian.yml @@ -0,0 +1,5 @@ +--- +__promtail_arch_map: + x86_64: 'amd64' + +__promtail_arch: "{{ __promtail_arch_map[ansible_architecture] | default(ansible_architecture) }}" diff --git a/roles/promtail/vars/RedHat.yml b/roles/promtail/vars/RedHat.yml new file mode 100644 index 00000000..0954ee3d --- /dev/null +++ b/roles/promtail/vars/RedHat.yml @@ -0,0 +1,2 @@ +--- +__promtail_arch: "{{ ansible_architecture }}" From 6442f7a5d177d6296dfec9112a1dd2ec52ef83b4 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 13 May 2024 10:36:58 +0300 Subject: [PATCH 5/7] Add a new config part to configure KeyCloak based auth (#191) Co-authored-by: Ishan Jain <51803183+ishanjainn@users.noreply.github.com> --- roles/grafana/defaults/main.yml | 15 +++++++++++++++ roles/grafana/templates/grafana.ini.j2 | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/roles/grafana/defaults/main.yml b/roles/grafana/defaults/main.yml index 12f3d7cc..3c640973 100644 --- a/roles/grafana/defaults/main.yml +++ b/roles/grafana/defaults/main.yml @@ -145,6 +145,21 @@ grafana_ldap: {} # - group_dn: "cn=alternative_admins,ou=groups,dc=grafana,dc=org" # org_role: Admin +# Grafana KeyCloak auth +grafana_auth_generic_oauth: {} +# enabled: true +# name: "Keycloak-OAuth" +# allow_sign_up: true +# client_id: YOUR_APP_CLIENT_ID +# client_secret: YOUR_APP_CLIENT_SECRET +# scopes: "openid email profile offline_access roles" +# email_attribute_path: email +# login_attribute_path: username +# name_attribute_path: full_name +# auth_url: "https:///realms//protocol/openid-connect/auth" +# token_url: "https:///realms//protocol/openid-connect/token" +# api_url: "https:///realms//protocol/openid-connect/userinfo" + grafana_session: {} # provider: file # provider_config: "sessions" diff --git a/roles/grafana/templates/grafana.ini.j2 b/roles/grafana/templates/grafana.ini.j2 index df6eab14..a18af8be 100644 --- a/roles/grafana/templates/grafana.ini.j2 +++ b/roles/grafana/templates/grafana.ini.j2 @@ -212,3 +212,11 @@ provider = {{ grafana_image_storage.provider }} {{ k }} = {{ v }} {% endfor %} {% endif %} + +# Oauth_Keycloack +{% if grafana_auth_generic_oauth != {} %} +[auth.generic_oauth] +{% for k,v in grafana_auth_generic_oauth.items() %} +{{ k }} = {{ v }} +{% endfor %} +{% endif %} From 1fd392ddf3166888ba60689897239e487c4cbbe2 Mon Sep 17 00:00:00 2001 From: ishanjainn Date: Mon, 13 May 2024 13:13:52 +0530 Subject: [PATCH 6/7] Release 5.2.0 --- CHANGELOG.rst | 12 +++++++++++- changelogs/.plugin-cache.yaml | 2 +- changelogs/changelog.yaml | 7 +++++++ galaxy.yml | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 605e99f9..e1d9762c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,10 +4,20 @@ Grafana.Grafana Release Notes .. contents:: Topics +v5.2.0 +====== + +Major Changes +------------- + +- Bump ansible-lint from 24.2.2 to 24.2.3 by @dependabot in https://github.com/grafana/grafana-ansible-collection/pull/195 +- Add promtail role by @voidquark in https://github.com/grafana/grafana-ansible-collection/pull/197 +- Add a new config part to configure KeyCloak based auth by @he0s in https://github.com/grafana/grafana-ansible-collection/pull/191 + v5.1.0 ====== -Minor Changes +Major Changes ------------- - fix: Uninstall Step for Loki and Mimir by @voidquark in https://github.com/grafana/grafana-ansible-collection/pull/193 diff --git a/changelogs/.plugin-cache.yaml b/changelogs/.plugin-cache.yaml index 5c853c6a..1d78dc03 100644 --- a/changelogs/.plugin-cache.yaml +++ b/changelogs/.plugin-cache.yaml @@ -56,4 +56,4 @@ plugins: strategy: {} test: {} vars: {} -version: 5.1.0 +version: 5.2.0 diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 6a4178c7..bdf0debd 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -276,3 +276,10 @@ releases: major_changes: - fix: Uninstall Step for Loki and Mimir by @voidquark in https://github.com/grafana/grafana-ansible-collection/pull/193 release_date: '2024-05-07' + 5.2.0: + changes: + major_changes: + - Bump ansible-lint from 24.2.2 to 24.2.3 by @dependabot in https://github.com/grafana/grafana-ansible-collection/pull/195 + - Add promtail role by @voidquark in https://github.com/grafana/grafana-ansible-collection/pull/197 + - Add a new config part to configure KeyCloak based auth by @he0s in https://github.com/grafana/grafana-ansible-collection/pull/191 + release_date: '2024-05-13' diff --git a/galaxy.yml b/galaxy.yml index 59c74ef6..03b74ccf 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: grafana name: grafana -version: 5.1.0 +version: 5.2.0 readme: README.md authors: - Grafana Labs From 7933edaf991a2962bbec5878eb6f63a7e0ddd3d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 16:36:38 +0000 Subject: [PATCH 7/7] Bump pylint from 3.1.0 to 3.1.1 Bumps [pylint](https://github.com/pylint-dev/pylint) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/pylint-dev/pylint/releases) - [Commits](https://github.com/pylint-dev/pylint/compare/v3.1.0...v3.1.1) --- updated-dependencies: - dependency-name: pylint dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Pipfile.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 704c72ed..70fe7612 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -427,12 +427,12 @@ }, "pylint": { "hashes": [ - "sha256:507a5b60953874766d8a366e8e8c7af63e058b26345cfcb5f91f89d987fd6b74", - "sha256:6a69beb4a6f63debebaab0a3477ecd0f559aa726af4954fc948c51f7a2549e23" + "sha256:862eddf25dab42704c5f06d3688b8bc19ef4c99ad8a836b6ff260a3b2fbafee1", + "sha256:c7c2652bf8099c7fb7a63bc6af5c5f8f7b9d7b392fa1d320cb020e222aff28c2" ], "index": "pypi", "markers": "python_full_version >= '3.8.0'", - "version": "==3.1.0" + "version": "==3.1.1" }, "pyyaml": { "hashes": [ @@ -709,11 +709,11 @@ }, "tomlkit": { "hashes": [ - "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b", - "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3" + "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f", + "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c" ], "markers": "python_version >= '3.7'", - "version": "==0.12.4" + "version": "==0.12.5" }, "typing-extensions": { "hashes": [