diff --git a/roles/process_exporter/README.md b/roles/process_exporter/README.md new file mode 100644 index 000000000..c00f825ed --- /dev/null +++ b/roles/process_exporter/README.md @@ -0,0 +1,27 @@ +# Ansible Role: process_exporter + +## Description + +Deploy [process-exporter](https://github.com/ncabatoff/process-exporter) using ansible. + +Note. This repository and role uses the name process_exporter to conform with ansible galaxy constraints. + +## Requirements + +- Ansible >= 2.9 (It might work on previous versions, but we cannot guarantee it) + +## Role Variables + +All variables which can be overridden are stored in [meta/argument_specs.yml](meta/argument_specs.yml) file. +See the [prometheus.prometheus.process_exporter](https://prometheus-community.github.io/ansible/branch/main/process_exporter_role.html) docs. + +## Example + +### Playbook + +Use it in a playbook as follows: +```yaml +- hosts: all + roles: + - prometheus.prometheus.process_exporter +``` diff --git a/roles/process_exporter/defaults/main.yml b/roles/process_exporter/defaults/main.yml new file mode 100644 index 000000000..e12050a3b --- /dev/null +++ b/roles/process_exporter/defaults/main.yml @@ -0,0 +1,32 @@ +--- +process_exporter_version: 0.7.10 +process_exporter_binary_local_dir: "" +process_exporter_binary_url: "https://github.com/{{ _process_exporter_repo }}/releases/download/v{{ process_exporter_version }}/\ + process-exporter-{{ process_exporter_version }}.linux-{{ go_arch }}.tar.gz" +process_exporter_checksums_url: "https://github.com/{{ _process_exporter_repo }}/releases/download/v{{ process_exporter_version }}/checksums.txt" +process_exporter_skip_install: false +process_exporter_archive_path: /tmp + + +process_exporter_web_listen_address: "0.0.0.0:9256" +process_exporter_web_telemetry_path: "/metrics" + +process_exporter_tls_server_config: {} + +process_exporter_http_server_config: {} + +process_exporter_basic_auth_users: {} + +# Process names +# "raw" section is needed to avoid attempted interpretation +# of process-exporter Template varables (like {{.Comm}}) +process_exporter_names: | + {% raw %} + - name: "{{.Comm}}" + cmdline: + - '.+' + {% endraw %} + +process_exporter_binary_install_dir: "/usr/local/bin" +process_exporter_system_group: "process-exp" +process_exporter_system_user: "{{ process_exporter_system_group }}" diff --git a/roles/process_exporter/handlers/main.yml b/roles/process_exporter/handlers/main.yml new file mode 100644 index 000000000..7b17604f9 --- /dev/null +++ b/roles/process_exporter/handlers/main.yml @@ -0,0 +1,8 @@ +--- +- name: Restart process_exporter + listen: "restart process_exporter" + become: true + ansible.builtin.systemd: + daemon_reload: true + name: process_exporter + state: restarted diff --git a/roles/process_exporter/meta/argument_specs.yml b/roles/process_exporter/meta/argument_specs.yml new file mode 100644 index 000000000..0d959a863 --- /dev/null +++ b/roles/process_exporter/meta/argument_specs.yml @@ -0,0 +1,69 @@ +--- +# yamllint disable rule:line-length +argument_specs: + main: + short_description: "Prometheus Process exporter" + description: + - "Deploy prometheus L(Process exporter,https://github.com/ncabatoff/process_exporter) using ansible" + author: + - "Prometheus Community" + options: + process_exporter_version: + description: "Process exporter package version. Also accepts latest as parameter." + default: "0.7.5" + process_exporter_skip_install: + description: "Process exporter installation tasks gets skipped when set to true." + type: bool + default: false + process_exporter_binary_local_dir: + description: + - "Enables the use of local packages instead of those distributed on github." + - "The parameter may be set to a directory where the C(process_exporter) binary is stored on the host where ansible is run." + - "This overrides the I(process_exporter_version) parameter" + process_exporter_archive_path: + description: "Local path to stash the archive and its extraction" + default: "/tmp" + process_exporter_binary_url: + description: "URL of the Process exporter binaries .tar.gz file" + default: "https://github.com/{{ _process_exporter_repo }}/releases/download/v{{ process_exporter_version }}/process_exporter-{{ process_exporter_version }}.linux-{{ go_arch }}.tar.gz" + process_exporter_checksums_url: + description: "URL of the Process exporter checksums file" + default: "https://github.com/{{ _process_exporter_repo }}/releases/download/v{{ process_exporter_version }}/checksums.txt" + process_exporter_web_listen_address: + description: "Address on which Process exporter will listen" + default: "0.0.0.0:9256" + process_exporter_web_telemetry_path: + description: "Path under which to expose metrics" + default: "/metrics" + process_exporter_tls_server_config: + description: + - "Configuration for TLS authentication." + type: "dict" + process_exporter_http_server_config: + description: + - "Config for HTTP/2 support." + type: "dict" + process_exporter_basic_auth_users: + description: "Dictionary of users and password for basic authentication. Passwords are automatically hashed with bcrypt." + type: "dict" + process_exporter_names: + description: + - "Processes which should be monitored." + - "Syntax is the same as in" + - "L(using-a-config-file Default is consistent with deb/rpm packages,https://github.com/ncabatoff/process-exporter#using-a-config-file Default is consistent with deb/rpm packages)" + default: !unsafe "[{name: '{{.Comm}}', cmdline: [.+]}]" + process_exporter_binary_install_dir: + description: + - "I(Advanced)" + - "Directory to install process_exporter binary" + default: "/usr/local/bin" + process_exporter_system_group: + description: + - "I(Advanced)" + - "System group for Process exporter" + default: "process-exp" + process_exporter_system_user: + description: + - "I(Advanced)" + - "Process exporter user" + default: "process-exp" diff --git a/roles/process_exporter/meta/main.yml b/roles/process_exporter/meta/main.yml new file mode 100644 index 000000000..5c89712fa --- /dev/null +++ b/roles/process_exporter/meta/main.yml @@ -0,0 +1,30 @@ +--- +galaxy_info: + author: "Prometheus Community" + description: "Prometheus Process Exporter" + license: "Apache" + min_ansible_version: "2.9" + platforms: + - name: "Ubuntu" + versions: + - "focal" + - "jammy" + - name: "Debian" + versions: + - "bullseye" + - "buster" + - name: "EL" + versions: + - "7" + - "8" + - "9" + - name: "Fedora" + versions: + - "37" + - '38' + galaxy_tags: + - "monitoring" + - "prometheus" + - "exporter" + - "metrics" + - "system" diff --git a/roles/process_exporter/molecule/alternative/molecule.yml b/roles/process_exporter/molecule/alternative/molecule.yml new file mode 100644 index 000000000..8b6b51fc4 --- /dev/null +++ b/roles/process_exporter/molecule/alternative/molecule.yml @@ -0,0 +1,28 @@ +--- +provisioner: + inventory: + group_vars: + all: + process_exporter_binary_local_dir: "/tmp/process_exporter-linux-amd64" + process_exporter_web_listen_address: "127.0.0.1:8080" + process_exporter_tls_server_config: + cert_file: /etc/process_exporter/tls.cert + key_file: /etc/process_exporter/tls.key + process_exporter_http_server_config: + http2: true + process_exporter_basic_auth_users: + randomuser: examplepassword + go_arch: amd64 + process_exporter_version: 0.7.10 + process_exporter_names: | + {% raw %} + - name: "{{.Comm}}" + cmdline: + - systemd + - name: "{{.Comm}}" + cmdline: + - systemd-journald + - name: "{{.Comm}}" + cmdline: + - crond + {% endraw %} diff --git a/roles/process_exporter/molecule/alternative/prepare.yml b/roles/process_exporter/molecule/alternative/prepare.yml new file mode 100644 index 000000000..92769f434 --- /dev/null +++ b/roles/process_exporter/molecule/alternative/prepare.yml @@ -0,0 +1,77 @@ +--- +- name: Run local preparation + hosts: localhost + gather_facts: false + tasks: + - name: Download process_exporter binary to local folder + become: false + ansible.builtin.get_url: + url: "https://github.com/ncabatoff/process-exporter/releases/download/v{{\ + \ process_exporter_version }}/process-exporter-{{ process_exporter_version }}.linux-{{\ + \ go_arch }}.tar.gz" + dest: "/tmp/process_exporter-{{ process_exporter_version }}.linux-{{ go_arch }}.tar.gz" + mode: 0644 + register: _download_binary + until: _download_binary is succeeded + retries: 5 + delay: 2 + check_mode: false + + - name: Unpack process_exporter binary + become: false + ansible.builtin.unarchive: + src: "/tmp/process_exporter-{{ process_exporter_version }}.linux-{{ go_arch }}.tar.gz" + dest: "/tmp" + creates: "/tmp/process-exporter-{{ process_exporter_version }}.linux-{{ go_arch }}/process-exporter" + check_mode: false + + - name: Link to process_exporter binaries directory + become: false + ansible.builtin.file: + src: "/tmp/process-exporter-{{ process_exporter_version }}.linux-amd64" + dest: "/tmp/process_exporter-linux-amd64" + state: link + check_mode: false + + - name: Install pyOpenSSL for certificate generation + ansible.builtin.pip: + name: "pyOpenSSL" + + - name: Create private key + community.crypto.openssl_privatekey: + path: "/tmp/tls.key" + + - name: Create CSR + community.crypto.openssl_csr: + path: "/tmp/tls.csr" + privatekey_path: "/tmp/tls.key" + + - name: Create certificate + community.crypto.x509_certificate: + path: "/tmp/tls.cert" + csr_path: "/tmp/tls.csr" + privatekey_path: "/tmp/tls.key" + provider: selfsigned + +- name: Run target preparation + hosts: all + any_errors_fatal: true + tasks: + - name: Create process_exporter cert dir + ansible.builtin.file: + path: "{{ process_exporter_tls_server_config.cert_file | dirname }}" + state: directory + owner: root + group: root + mode: u+rwX,g+rwX,o=rX + + - name: Copy cert and key + ansible.builtin.copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: "{{ item.mode | default('0644') }}" + loop: + - src: "/tmp/tls.cert" + dest: "{{ process_exporter_tls_server_config.cert_file }}" + - src: "/tmp/tls.key" + dest: "{{ process_exporter_tls_server_config.key_file }}" diff --git a/roles/process_exporter/molecule/alternative/tests/test_alternative.py b/roles/process_exporter/molecule/alternative/tests/test_alternative.py new file mode 100644 index 000000000..4922514b0 --- /dev/null +++ b/roles/process_exporter/molecule/alternative/tests/test_alternative.py @@ -0,0 +1,45 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_directories(host): + dirs = [ + "/var/lib/process_exporter" + ] + for dir in dirs: + d = host.file(dir) + assert not d.exists + + +def test_service(host): + s = host.service("process_exporter") + try: + assert s.is_running + except AssertionError: + # Capture service logs + journal_output = host.run('journalctl -u process_exporter --since "1 hour ago"') + print("\n==== journalctl -u process_exporter Output ====\n") + print(journal_output) + print("\n============================================\n") + raise # Re-raise the original assertion error + + +def test_protecthome_property(host): + s = host.service("process_exporter") + p = s.systemd_properties + assert p.get("ProtectHome") == "yes" + + +def test_socket(host): + sockets = [ + "tcp://127.0.0.1:8080" + ] + for socket in sockets: + s = host.socket(socket) + assert s.is_listening diff --git a/roles/process_exporter/molecule/default/molecule.yml b/roles/process_exporter/molecule/default/molecule.yml new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/roles/process_exporter/molecule/default/molecule.yml @@ -0,0 +1 @@ +--- diff --git a/roles/process_exporter/molecule/default/tests/test_default.py b/roles/process_exporter/molecule/default/tests/test_default.py new file mode 100644 index 000000000..71ea4d365 --- /dev/null +++ b/roles/process_exporter/molecule/default/tests/test_default.py @@ -0,0 +1,79 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_directories(host): + dirs = [ + "/etc/process_exporter" + ] + for dir in dirs: + d = host.file(dir) + assert d.is_directory + assert d.exists + + +def test_files(host): + files = [ + "/etc/systemd/system/process_exporter.service", + "/usr/local/bin/process_exporter", + ] + for file in files: + f = host.file(file) + assert f.exists + assert f.is_file + + +def test_permissions_didnt_change(host): + dirs = [ + "/etc", + "/root", + "/usr", + "/var" + ] + for file in dirs: + f = host.file(file) + assert f.exists + assert f.is_directory + assert f.user == "root" + assert f.group == "root" + + +def test_user(host): + assert host.group("process-exp").exists + assert "process-exp" in host.user("process-exp").groups + assert host.user("process-exp").shell == "/usr/sbin/nologin" + assert host.user("process-exp").home == "/" + + +def test_service(host): + s = host.service("process_exporter") + try: + assert s.is_running + except AssertionError: + # Capture service logs + journal_output = host.run('journalctl -u process_exporter --since "1 hour ago"') + print("\n==== journalctl -u process_exporter Output ====\n") + print(journal_output) + print("\n============================================\n") + raise # Re-raise the original assertion error + + +def test_protecthome_property(host): + s = host.service("process_exporter") + p = s.systemd_properties + assert p.get("ProtectHome") == "yes" + + +def test_socket(host): + sockets = [ + "tcp://0.0.0.0:9256" + ] + for socket in sockets: + s = host.socket(socket) + assert s.is_listening diff --git a/roles/process_exporter/molecule/latest/molecule.yml b/roles/process_exporter/molecule/latest/molecule.yml new file mode 100644 index 000000000..66b930bc2 --- /dev/null +++ b/roles/process_exporter/molecule/latest/molecule.yml @@ -0,0 +1,6 @@ +--- +provisioner: + inventory: + group_vars: + all: + process_exporter_version: latest diff --git a/roles/process_exporter/molecule/latest/tests/test_latest.py b/roles/process_exporter/molecule/latest/tests/test_latest.py new file mode 100644 index 000000000..63e5d1563 --- /dev/null +++ b/roles/process_exporter/molecule/latest/tests/test_latest.py @@ -0,0 +1,43 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import testinfra.utils.ansible_runner +import pytest + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +@pytest.mark.parametrize("files", [ + "/etc/systemd/system/process_exporter.service", + "/usr/local/bin/process_exporter" +]) +def test_files(host, files): + f = host.file(files) + assert f.exists + assert f.is_file + + +def test_service(host): + s = host.service("process_exporter") + try: + assert s.is_running + except AssertionError: + # Capture service logs + journal_output = host.run('journalctl -u process_exporter --since "1 hour ago"') + print("\n==== journalctl -u process_exporter Output ====\n") + print(journal_output) + print("\n============================================\n") + raise # Re-raise the original assertion error + + +def test_protecthome_property(host): + s = host.service("process_exporter") + p = s.systemd_properties + assert p.get("ProtectHome") == "yes" + + +def test_socket(host): + s = host.socket("tcp://0.0.0.0:9256") + assert s.is_listening diff --git a/roles/process_exporter/tasks/configure.yml b/roles/process_exporter/tasks/configure.yml new file mode 100644 index 000000000..de82483f4 --- /dev/null +++ b/roles/process_exporter/tasks/configure.yml @@ -0,0 +1,51 @@ +--- +- name: Copy the process_exporter systemd service file + ansible.builtin.template: + src: process_exporter.service.j2 + dest: /etc/systemd/system/process_exporter.service + owner: root + group: root + mode: 0644 + notify: restart process_exporter + +- name: Create process_exporter config directory + ansible.builtin.file: + path: "/etc/process_exporter" + state: directory + owner: root + group: root + mode: u+rwX,g+rwX,o=rX + +- name: Create/Update configuration file + ansible.builtin.template: + src: "config.yml.j2" + dest: "/etc/process_exporter/config.yml" + owner: root + group: root + mode: 0644 + when: + - process_exporter_names != [] + notify: restart process_exporter + +- name: Configure process_exporter web config + ansible.builtin.template: + src: "web_config.yml.j2" + dest: "/etc/process_exporter/web_config.yml" + owner: root + group: root + mode: 0644 + when: + ( process_exporter_tls_server_config | length > 0 ) or + ( process_exporter_http_server_config | length > 0 ) or + ( process_exporter_basic_auth_users | length > 0 ) + notify: restart process_exporter + +- name: Allow process_exporter port in SELinux on RedHat OS family + community.general.seport: + ports: "{{ process_exporter_web_listen_address.split(':')[-1] }}" + proto: tcp + setype: http_port_t + state: present + when: + - ansible_version.full is version_compare('2.4', '>=') + - ansible_selinux.status == "enabled" diff --git a/roles/process_exporter/tasks/install.yml b/roles/process_exporter/tasks/install.yml new file mode 100644 index 000000000..e4e2a984e --- /dev/null +++ b/roles/process_exporter/tasks/install.yml @@ -0,0 +1,69 @@ +--- +- name: Create the process_exporter group + ansible.builtin.group: + name: "{{ process_exporter_system_group }}" + state: present + system: true + when: process_exporter_system_group != "root" + +- name: Create the process_exporter user + ansible.builtin.user: + name: "{{ process_exporter_system_user }}" + groups: "{{ process_exporter_system_group }}" + append: true + shell: /usr/sbin/nologin + system: true + create_home: false + home: / + when: process_exporter_system_user != "root" + +- name: Get binary + when: + - process_exporter_binary_local_dir | length == 0 + - not process_exporter_skip_install + block: + + - name: Download process_exporter binary to local folder + become: false + ansible.builtin.get_url: + url: "{{ process_exporter_binary_url }}" + dest: "{{ process_exporter_archive_path }}/process_exporter-{{ process_exporter_version }}.linux-{{ go_arch }}.tar.gz" + checksum: "sha256:{{ __process_exporter_checksum }}" + mode: '0644' + register: _download_binary + until: _download_binary is succeeded + retries: 5 + delay: 2 + delegate_to: localhost + check_mode: false + + - name: Unpack process_exporter binary + become: false + ansible.builtin.unarchive: + src: "{{ process_exporter_archive_path }}/process_exporter-{{ process_exporter_version }}.linux-{{ go_arch }}.tar.gz" + dest: "{{ process_exporter_archive_path }}" + creates: "{{ process_exporter_archive_path }}/process-exporter-{{ process_exporter_version }}.linux-{{ go_arch }}/process-exporter" + delegate_to: localhost + check_mode: false + + - name: Propagate process_exporter binaries + ansible.builtin.copy: + src: "{{ process_exporter_archive_path }}/process-exporter-{{ process_exporter_version }}.linux-{{ go_arch }}/process-exporter" + dest: "{{ process_exporter_binary_install_dir }}/process_exporter" + mode: 0755 + owner: root + group: root + notify: restart process_exporter + when: not ansible_check_mode + +- name: Propagate locally distributed process_exporter binary + ansible.builtin.copy: + src: "{{ process_exporter_binary_local_dir }}/process-exporter" + dest: "{{ process_exporter_binary_install_dir }}/process_exporter" + mode: 0755 + owner: root + group: root + when: + - process_exporter_binary_local_dir | length > 0 + - not process_exporter_skip_install + notify: restart process_exporter diff --git a/roles/process_exporter/tasks/main.yml b/roles/process_exporter/tasks/main.yml new file mode 100644 index 000000000..44ee66d6a --- /dev/null +++ b/roles/process_exporter/tasks/main.yml @@ -0,0 +1,56 @@ +--- +- name: Preflight + ansible.builtin.include_tasks: + file: preflight.yml + apply: + tags: + - process_exporter_install + - process_exporter_configure + - process_exporter_run + tags: + - process_exporter_install + - process_exporter_configure + - process_exporter_run + +- name: Install + ansible.builtin.include_tasks: + file: install.yml + apply: + become: true + tags: + - process_exporter_install + tags: + - process_exporter_install + +- name: SELinux + ansible.builtin.include_tasks: + file: selinux.yml + apply: + become: true + tags: + - process_exporter_configure + when: ansible_selinux.status == "enabled" + tags: + - process_exporter_configure + +- name: Configure + ansible.builtin.include_tasks: + file: configure.yml + apply: + become: true + tags: + - process_exporter_configure + tags: + - process_exporter_configure + +- name: Ensure process_exporter is enabled on boot + become: true + ansible.builtin.systemd: + daemon_reload: true + name: process_exporter + enabled: true + state: started + when: + - not ansible_check_mode + tags: + - process_exporter_run diff --git a/roles/process_exporter/tasks/preflight.yml b/roles/process_exporter/tasks/preflight.yml new file mode 100644 index 000000000..77bb34735 --- /dev/null +++ b/roles/process_exporter/tasks/preflight.yml @@ -0,0 +1,73 @@ +--- +- name: Assert usage of systemd as an init system + ansible.builtin.assert: + that: ansible_service_mgr == 'systemd' + msg: "This role only works with systemd" + +- name: Install package fact dependencies + become: true + ansible.builtin.package: + name: "{{ _pkg_fact_req }}" + state: present + when: (_pkg_fact_req) + vars: + _pkg_fact_req: "{% if (ansible_pkg_mgr == 'apt') %}\ + {{ ('python-apt' if ansible_python_version is version('3', '<') else 'python3-apt') }} + {% else %}\ + {% endif %}" + +- name: Gather package facts + ansible.builtin.package_facts: + when: "not 'packages' in ansible_facts" + +- name: Naive assertion of proper listen address + ansible.builtin.assert: + that: + - "':' in process_exporter_web_listen_address" + +- name: Check if process_exporter is installed + ansible.builtin.stat: + path: "{{ process_exporter_binary_install_dir }}/process_exporter" + register: __process_exporter_is_installed + check_mode: false + tags: + - process_exporter_install + +- name: Gather currently installed process_exporter version (if any) + ansible.builtin.command: "{{ process_exporter_binary_install_dir }}/process_exporter --version" + changed_when: false + register: __process_exporter_current_version_output + check_mode: false + when: __process_exporter_is_installed.stat.exists + tags: + - process_exporter_install + +- name: Discover latest version + ansible.builtin.set_fact: + process_exporter_version: "{{ (lookup('url', 'https://api.github.com/repos/{{ _process_exporter_repo }}/releases/latest', headers=_github_api_headers, + split_lines=False) | from_json).get('tag_name') | replace('v', '') }}" + run_once: true + until: process_exporter_version is version('0.0.0', '>=') + retries: 10 + when: + - process_exporter_version == "latest" + - process_exporter_binary_local_dir | length == 0 + - not process_exporter_skip_install + +- name: Get process_exporter binary checksum + when: + - process_exporter_binary_local_dir | length == 0 + - not process_exporter_skip_install + block: + - name: Get checksum list from github + ansible.builtin.set_fact: + __process_exporter_checksums: "{{ lookup('url', process_exporter_checksums_url, headers=_github_api_headers, wantlist=True) | list }}" + run_once: true + until: __process_exporter_checksums is search('linux-' + go_arch + '.tar.gz') + retries: 10 + + - name: "Get checksum for {{ go_arch }}" + ansible.builtin.set_fact: + __process_exporter_checksum: "{{ item.split(' ')[0] }}" + with_items: "{{ __process_exporter_checksums }}" + when: "('linux-' + go_arch + '.tar.gz') in item" diff --git a/roles/process_exporter/tasks/selinux.yml b/roles/process_exporter/tasks/selinux.yml new file mode 100644 index 000000000..754cbd0a2 --- /dev/null +++ b/roles/process_exporter/tasks/selinux.yml @@ -0,0 +1,23 @@ +--- +- name: Install selinux python packages [RedHat] + ansible.builtin.package: + name: "{{ ['libselinux-python', 'policycoreutils-python'] + if ansible_python_version is version('3', '<') else + ['python3-libselinux', 'python3-policycoreutils'] }}" + state: present + register: _install_selinux_packages + until: _install_selinux_packages is success + retries: 5 + delay: 2 + when: ansible_os_family | lower == "redhat" + +- name: Install selinux python packages [clearlinux] + ansible.builtin.package: + name: sysadmin-basic + state: present + register: _install_selinux_packages + until: _install_selinux_packages is success + retries: 5 + delay: 2 + when: + - ansible_distribution | lower == "clearlinux" diff --git a/roles/process_exporter/templates/config.yml.j2 b/roles/process_exporter/templates/config.yml.j2 new file mode 100644 index 000000000..8769eed84 --- /dev/null +++ b/roles/process_exporter/templates/config.yml.j2 @@ -0,0 +1,5 @@ +--- +{{ ansible_managed | comment }} + +process_names: +{{ process_exporter_names }} diff --git a/roles/process_exporter/templates/process_exporter.service.j2 b/roles/process_exporter/templates/process_exporter.service.j2 new file mode 100644 index 000000000..b45f7031a --- /dev/null +++ b/roles/process_exporter/templates/process_exporter.service.j2 @@ -0,0 +1,43 @@ +{{ ansible_managed | comment }} + +[Unit] +Description=Prometheus Process Exporter +After=network-online.target + +[Service] +Type=simple +User={{ process_exporter_system_user }} +Group={{ process_exporter_system_group }} +ExecStart={{ process_exporter_binary_install_dir }}/process_exporter \ +{% if process_exporter_names != [] -%} + '--config.path=/etc/process_exporter/config.yml' \ +{% endif -%} +{% if process_exporter_tls_server_config | length > 0 or process_exporter_http_server_config | length > 0 or process_exporter_basic_auth_users | length > 0 %} + '--web.config.file=/etc/process_exporter/web_config.yml' \ +{% endif %} + '--web.listen-address={{ process_exporter_web_listen_address }}' \ + '--web.telemetry-path={{ process_exporter_web_telemetry_path }}' + +SyslogIdentifier=process_exporter +Restart=always +RestartSec=1 +StartLimitInterval=0 + +{% set ns = namespace(protect_home = 'yes') %} +{% for m in ansible_mounts if m.mount.startswith('/home') %} +{% set ns.protect_home = 'read-only' %} +{% endfor %} +ProtectHome={{ ns.protect_home }} +NoNewPrivileges=yes + +{% if (ansible_facts.packages.systemd | first).version is version('232', '>=') %} +ProtectSystem=strict +ProtectControlGroups=true +ProtectKernelModules=true +ProtectKernelTunables=yes +{% else %} +ProtectSystem=full +{% endif %} + +[Install] +WantedBy=multi-user.target diff --git a/roles/process_exporter/templates/web_config.yml.j2 b/roles/process_exporter/templates/web_config.yml.j2 new file mode 100644 index 000000000..3ebf90d59 --- /dev/null +++ b/roles/process_exporter/templates/web_config.yml.j2 @@ -0,0 +1,19 @@ +--- +{{ ansible_managed | comment }} + +{% if process_exporter_tls_server_config | length > 0 %} +tls_server_config: +{{ process_exporter_tls_server_config | to_nice_yaml | indent(2, true) }} +{% endif %} + +{% if process_exporter_http_server_config | length > 0 %} +http_server_config: +{{ process_exporter_http_server_config | to_nice_yaml | indent(2, true) }} +{% endif %} + +{% if process_exporter_basic_auth_users | length > 0 %} +basic_auth_users: +{% for k, v in process_exporter_basic_auth_users.items() %} + {{ k }}: {{ v | string | password_hash('bcrypt', ('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' | shuffle(seed=inventory_hostname) | join)[:22], rounds=9) }} +{% endfor %} +{% endif %} diff --git a/roles/process_exporter/test-requirements.txt b/roles/process_exporter/test-requirements.txt new file mode 100644 index 000000000..7f0b6e759 --- /dev/null +++ b/roles/process_exporter/test-requirements.txt @@ -0,0 +1 @@ +bcrypt diff --git a/roles/process_exporter/vars/main.yml b/roles/process_exporter/vars/main.yml new file mode 100644 index 000000000..b31254ff6 --- /dev/null +++ b/roles/process_exporter/vars/main.yml @@ -0,0 +1,11 @@ +--- +go_arch_map: + i386: '386' + x86_64: 'amd64' + aarch64: 'arm64' + armv7l: 'armv7' + armv6l: 'armv6' + +go_arch: "{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}" +_process_exporter_repo: "ncabatoff/process-exporter" +_github_api_headers: "{{ {'GITHUB_TOKEN': lookup('ansible.builtin.env', 'GITHUB_TOKEN')} if (lookup('ansible.builtin.env', 'GITHUB_TOKEN')) else {} }}" diff --git a/tests/integration/targets/molecule-process_exporter-alternative/runme.sh b/tests/integration/targets/molecule-process_exporter-alternative/runme.sh new file mode 100755 index 000000000..d094c3e1b --- /dev/null +++ b/tests/integration/targets/molecule-process_exporter-alternative/runme.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +collection_root=$(pwd | grep -oP ".+\/ansible_collections\/\w+?\/\w+") +source "$collection_root/tests/integration/molecule.sh" diff --git a/tests/integration/targets/molecule-process_exporter-default/runme.sh b/tests/integration/targets/molecule-process_exporter-default/runme.sh new file mode 100755 index 000000000..d094c3e1b --- /dev/null +++ b/tests/integration/targets/molecule-process_exporter-default/runme.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +collection_root=$(pwd | grep -oP ".+\/ansible_collections\/\w+?\/\w+") +source "$collection_root/tests/integration/molecule.sh" diff --git a/tests/integration/targets/molecule-process_exporter-latest/runme.sh b/tests/integration/targets/molecule-process_exporter-latest/runme.sh new file mode 100755 index 000000000..d094c3e1b --- /dev/null +++ b/tests/integration/targets/molecule-process_exporter-latest/runme.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +collection_root=$(pwd | grep -oP ".+\/ansible_collections\/\w+?\/\w+") +source "$collection_root/tests/integration/molecule.sh"