Files

225 lines
8.7 KiB
YAML

---
# Both exporters listen on all addresses (the node exporter on host_exporters_listen_address if set); host_firewall
# limits who reaches them.
# Its recommends (smartmontools, nvme-cli, ipmitool) start units that fail on hosts without such hardware.
- name: Install the node exporter
ansible.builtin.apt:
name: prometheus-node-exporter
install_recommends: false
state: present
- name: Bind the node exporter to one address
ansible.builtin.lineinfile:
path: /etc/default/prometheus-node-exporter
regexp: '^ARGS='
line: 'ARGS="--web.listen-address={{ host_exporters_listen_address }}:9100"'
when: host_exporters_listen_address | length > 0
register: host_exporters_listen
# Check mode does not install the package.
ignore_errors: "{{ ansible_check_mode }}"
- name: Create the node exporter unit drop-in directory
ansible.builtin.file:
path: /etc/systemd/system/prometheus-node-exporter.service.d
state: directory
mode: "0755"
when: host_exporters_listen_address | length > 0
# The NetBird address exists only after the daemon is up, and a failed bind must not exhaust the start limit.
- name: Start the bound node exporter after NetBird and retry
ansible.builtin.copy:
dest: /etc/systemd/system/prometheus-node-exporter.service.d/listen-address.conf
mode: "0644"
content: |
[Unit]
After=netbird.service
StartLimitIntervalSec=0
[Service]
RestartSec=5s
when: host_exporters_listen_address | length > 0
register: host_exporters_listen_unit
- name: Enable the node exporter
ansible.builtin.systemd:
name: prometheus-node-exporter
enabled: true
state: "{{ 'restarted' if (host_exporters_listen.changed or host_exporters_listen_unit.changed) else 'started' }}"
daemon_reload: "{{ host_exporters_listen_unit.changed }}"
# Check mode does not install the package.
ignore_errors: "{{ ansible_check_mode }}"
- name: Install the smartctl exporter
when: host_exporters_smart
block:
- name: Look for an existing backports source
ansible.builtin.shell: >-
grep -rEqs '^[^#]*{{ ansible_distribution_release }}-backports'
--include='*.list' --include='*.sources' --exclude=host-exporters-backports.sources /etc/apt
register: host_exporters_backports
changed_when: false
failed_when: host_exporters_backports.rc > 1
check_mode: false
# Backports stay at priority 100, so only packages named with default_release come from there.
- name: Add the backports source
ansible.builtin.copy:
dest: /etc/apt/sources.list.d/host-exporters-backports.sources
mode: "0644"
content: |
Types: deb
URIs: http://deb.debian.org/debian
Suites: {{ ansible_distribution_release }}-backports
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
register: host_exporters_source
when: host_exporters_backports.rc == 1
# The module rejects default_release while the release is missing from its package cache.
- name: Look for the backports release in the package lists
ansible.builtin.shell: apt-cache policy | grep -q 'n={{ ansible_distribution_release }}-backports'
register: host_exporters_lists
changed_when: false
failed_when: false
check_mode: false
- name: Refresh the package lists for the backports source
ansible.builtin.apt:
update_cache: true
when: host_exporters_lists.rc != 0
- name: Install the smartctl exporter from backports
ansible.builtin.apt:
name: prometheus-smartctl-exporter
default_release: "{{ ansible_distribution_release }}-backports"
state: present
# Check mode does not write the backports source.
ignore_errors: "{{ ansible_check_mode }}"
# The packaged unit runs as root, which smartctl needs for the disks.
- name: Enable the smartctl exporter
ansible.builtin.systemd:
name: smartctl_exporter
enabled: true
state: started
ignore_errors: "{{ ansible_check_mode }}"
# Reads the BMC through /dev/ipmi0, read-only: no raw commands, no configuration.
# FreeIPMI refuses in-band access for any uid but 0, so the exporter runs as the packaged
# unprivileged user prometheus and starts the FreeIPMI tools it needs through sudo.
- name: Install the IPMI exporter
when: host_exporters_ipmi
block:
- name: Install ipmitool and the IPMI exporter
ansible.builtin.apt:
name:
- ipmitool
- sudo
- prometheus-ipmi-exporter
install_recommends: false
state: present
- name: Allow the exporter user to run the FreeIPMI tools
ansible.builtin.copy:
dest: /etc/sudoers.d/prometheus-ipmi-exporter
mode: "0440"
validate: visudo -cf %s
content: |
Defaults:prometheus !pam_session
{% for collector in host_exporters_ipmi_collectors %}
prometheus ALL = (root) NOPASSWD: /usr/sbin/{{ host_exporters_ipmi_tools[collector].tool }} {{ host_exporters_ipmi_tools[collector].args }} --config-file {{ host_exporters_ipmi_freeipmi_conf }}
{% endfor %}
register: host_exporters_ipmi_sudo
- name: Create the FreeIPMI configuration directory
ansible.builtin.file:
path: "{{ host_exporters_ipmi_freeipmi_conf | dirname }}"
state: directory
owner: root
group: root
mode: "0755"
# See the defaults for why the file is static.
- name: Write the FreeIPMI configuration
ansible.builtin.copy:
dest: "{{ host_exporters_ipmi_freeipmi_conf }}"
owner: root
group: root
mode: "0644"
content: |
# In-band access needs no settings. Not even sdr-cache-directory: the tools without an SDR cache
# reject it, and the cache of the ipmi tool stays in the home of root.
# collector_cmd replaces the tool itself, so each collector gets a wrapper that adds sudo. It swaps
# the exporter's --config-file for the static one. The exporter fills a named pipe at the path it
# passes and waits for a reader; the wrapper drains it so that writer does not hang.
- name: Create the sudo wrappers directory
ansible.builtin.file:
path: /usr/local/libexec/ipmi-exporter
state: directory
mode: "0755"
- name: Write the sudo wrappers
ansible.builtin.copy:
dest: /usr/local/libexec/ipmi-exporter/{{ item.key }}
mode: "0755"
content: |
#!/bin/sh
n=$#
while [ "$n" -gt 0 ]; do
a=$1; shift; n=$((n - 1))
if [ "$a" = --config-file ] && [ "$n" -gt 0 ]; then
timeout 5 cat "$1" > /dev/null 2>&1
shift; n=$((n - 1))
else
set -- "$@" "$a"
fi
done
exec sudo -n /usr/sbin/{{ item.value.tool }} "$@" --config-file {{ host_exporters_ipmi_freeipmi_conf }}
loop: "{{ host_exporters_ipmi_tools | dict2items | selectattr('key', 'in', host_exporters_ipmi_collectors) | list }}"
loop_control:
label: "{{ item.key }}"
register: host_exporters_ipmi_wrappers
- name: Write the IPMI exporter configuration
ansible.builtin.copy:
dest: /etc/prometheus/ipmi-local.yml
mode: "0644"
content: |
modules:
default:
collectors:
{% for collector in host_exporters_ipmi_collectors %}
- {{ collector }}
{% endfor %}
collector_cmd:
{% for collector in host_exporters_ipmi_collectors %}
{{ collector }}: /usr/local/libexec/ipmi-exporter/{{ collector }}
{% endfor %}
register: host_exporters_ipmi_config
- name: Create the IPMI exporter unit drop-in directory
ansible.builtin.file:
path: /etc/systemd/system/prometheus-ipmi-exporter.service.d
state: directory
mode: "0755"
# sudo needs setuid, so NoNewPrivileges stays off.
- name: Run the IPMI exporter with that configuration
ansible.builtin.copy:
dest: /etc/systemd/system/prometheus-ipmi-exporter.service.d/local.conf
mode: "0644"
content: |
[Service]
ExecStart=
ExecStart=/usr/bin/prometheus-ipmi-exporter --config.file=/etc/prometheus/ipmi-local.yml
register: host_exporters_ipmi_unit
- name: Enable the IPMI exporter
ansible.builtin.systemd:
name: prometheus-ipmi-exporter
enabled: true
state: "{{ 'restarted' if (host_exporters_ipmi_config.changed or host_exporters_ipmi_unit.changed or host_exporters_ipmi_wrappers.changed) else 'started' }}"
daemon_reload: true
ignore_errors: "{{ ansible_check_mode }}"