diff --git a/roles/blackbox_exporter/defaults/main.yml b/roles/blackbox_exporter/defaults/main.yml index f3bf56f76..b97af9bae 100644 --- a/roles/blackbox_exporter/defaults/main.yml +++ b/roles/blackbox_exporter/defaults/main.yml @@ -1,8 +1,10 @@ --- blackbox_exporter_version: 0.24.0 +blackbox_exporter_binary_local_dir: "" blackbox_exporter_binary_url: "https://github.com/{{ _blackbox_exporter_repo }}/releases/download/v{{ blackbox_exporter_version }}/\ blackbox_exporter-{{ blackbox_exporter_version }}.linux-{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}.tar.gz" +blackbox_exporter_checksums_url: "https://github.com/{{ _blackbox_exporter_repo }}/releases/download/v{{ blackbox_exporter_version }}/sha256sums.txt" blackbox_exporter_skip_install: false blackbox_exporter_web_listen_address: "0.0.0.0:9115" @@ -71,3 +73,5 @@ blackbox_exporter_configuration_modules: # Where to put the blackbox_exporter.yml main configuration file blackbox_exporter_config_dir: /etc + +blackbox_exporter_binary_install_dir: "/usr/local/bin" diff --git a/roles/blackbox_exporter/meta/argument_specs.yml b/roles/blackbox_exporter/meta/argument_specs.yml index ab97d1bfb..2938f698d 100644 --- a/roles/blackbox_exporter/meta/argument_specs.yml +++ b/roles/blackbox_exporter/meta/argument_specs.yml @@ -9,15 +9,23 @@ argument_specs: - "Prometheus Community" options: blackbox_exporter_version: - description: "Blackbox exporter package version" + description: "Blackbox exporter package version. Also accepts latest as parameter." default: "0.24.0" blackbox_exporter_skip_install: description: "Blackbox exporter installation tasks gets skipped when set to true." type: bool default: false + blackbox_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(blackbox_exporter) binary is stored on the host where ansible is run." + - "This overrides the I(blackbox_exporter_version) parameter" blackbox_exporter_binary_url: description: "URL of the blackbox_exporter binaries .tar.gz file" default: "https://github.com/{{ _blackbox_exporter_repo }}/releases/download/v{{ blackbox_exporter_version }}/blackbox_exporter-{{ blackbox_exporter_version }}.linux-{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}.tar.gz" + blackbox_exporter_checksums_url: + description: "URL of the blackbox exporter checksums file" + default: "https://github.com/{{ _blackbox_exporter_repo }}/releases/download/v{{ blackbox_exporter_version }}/sha256sums.txt" blackbox_exporter_web_listen_address: description: "Address on which blackbox exporter will be listening" default: "0.0.0.0:9115" @@ -37,6 +45,11 @@ argument_specs: blackbox_exporter_config_dir: description: "Directory where the blackbox exporter configuration file is placed" default: "/etc" + blackbox_exporter_binary_install_dir: + description: + - "I(Advanced)" + - "Directory to install blackbox_exporter binary" + default: "/usr/local/bin" blackbox_exporter_user: description: "The user the exporter runs as" default: "blackbox-exp" diff --git a/roles/blackbox_exporter/molecule/latest/molecule.yml b/roles/blackbox_exporter/molecule/latest/molecule.yml new file mode 100644 index 000000000..3e2b94705 --- /dev/null +++ b/roles/blackbox_exporter/molecule/latest/molecule.yml @@ -0,0 +1,6 @@ +--- +provisioner: + inventory: + group_vars: + all: + blackbox_exporter_version: latest diff --git a/roles/blackbox_exporter/molecule/latest/tests/test_latest.py b/roles/blackbox_exporter/molecule/latest/tests/test_latest.py new file mode 100644 index 000000000..8b5955eac --- /dev/null +++ b/roles/blackbox_exporter/molecule/latest/tests/test_latest.py @@ -0,0 +1,37 @@ +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/blackbox_exporter.service", + "/usr/local/bin/blackbox_exporter" +]) +def test_files(host, files): + f = host.file(files) + assert f.exists + assert f.is_file + + +def test_service(host): + s = host.service("blackbox_exporter") + try: + assert s.is_running + except AssertionError: + # Capture service logs + journal_output = host.run('journalctl -u blackbox_exporter --since "1 hour ago"') + print("\n==== journalctl -u blackbox_exporter Output ====\n") + print(journal_output) + print("\n============================================\n") + raise # Re-raise the original assertion error + + +def test_socket(host): + s = host.socket("tcp://0.0.0.0:9100") + assert s.is_listening diff --git a/roles/blackbox_exporter/tasks/install.yml b/roles/blackbox_exporter/tasks/install.yml index 777ae8a22..5d951f90f 100644 --- a/roles/blackbox_exporter/tasks/install.yml +++ b/roles/blackbox_exporter/tasks/install.yml @@ -15,33 +15,56 @@ createhome: false when: blackbox_exporter_user != 'root' -- name: Download blackbox exporter binary to local folder - become: false - ansible.builtin.unarchive: - src: "{{ blackbox_exporter_binary_url }}" - dest: "/tmp" - remote_src: true - creates: "/tmp/blackbox_exporter-{{ blackbox_exporter_version }}.linux-{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}/\ - blackbox_exporter" - register: _download_binary - until: _download_binary is succeeded - retries: 5 - delay: 2 - delegate_to: localhost - check_mode: false - when: not blackbox_exporter_skip_install +- name: Get binary + when: + - blackbox_exporter_binary_local_dir | length == 0 + - not blackbox_exporter_skip_install + block: + + - name: Download blackbox_exporter binary to local folder + become: false + ansible.builtin.get_url: + url: "{{ blackbox_exporter_binary_url }}" + dest: "/tmp/blackbox_exporter-{{ blackbox_exporter_version }}.linux-{{ go_arch }}.tar.gz" + checksum: "sha256:{{ __blackbox_exporter_checksum }}" + mode: '0644' + register: _download_binary + until: _download_binary is succeeded + retries: 5 + delay: 2 + delegate_to: localhost + check_mode: false -- name: Propagate blackbox exporter binary + - name: Unpack blackbox_exporter binary + become: false + ansible.builtin.unarchive: + src: "/tmp/blackbox_exporter-{{ blackbox_exporter_version }}.linux-{{ go_arch }}.tar.gz" + dest: "/tmp" + creates: "/tmp/blackbox_exporter-{{ blackbox_exporter_version }}.linux-{{ go_arch }}/blackbox_exporter" + delegate_to: localhost + check_mode: false + + - name: Propagate blackbox_exporter binaries + ansible.builtin.copy: + src: "/tmp/blackbox_exporter-{{ blackbox_exporter_version }}.linux-{{ go_arch }}/blackbox_exporter" + dest: "{{ blackbox_exporter_binary_install_dir }}/blackbox_exporter" + mode: 0755 + owner: root + group: root + notify: restart blackbox_exporter + when: not ansible_check_mode + +- name: Propagate locally distributed blackbox_exporter binary ansible.builtin.copy: - src: "/tmp/blackbox_exporter-{{ blackbox_exporter_version }}.linux-{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}/\ - blackbox_exporter" - dest: "/usr/local/bin/blackbox_exporter" - mode: 0750 + src: "{{ blackbox_exporter_binary_local_dir }}/blackbox_exporter" + dest: "{{ blackbox_exporter_binary_install_dir }}/blackbox_exporter" + mode: 0755 owner: root - group: "{{ blackbox_exporter_group }}" - when: not blackbox_exporter_skip_install - notify: - - restart blackbox exporter + group: root + when: + - blackbox_exporter_binary_local_dir | length > 0 + - not blackbox_exporter_skip_install + notify: restart blackbox_exporter - name: Install libcap on Debian systems ansible.builtin.package: diff --git a/roles/blackbox_exporter/tasks/preflight.yml b/roles/blackbox_exporter/tasks/preflight.yml index c3c7824fd..3deecc27c 100644 --- a/roles/blackbox_exporter/tasks/preflight.yml +++ b/roles/blackbox_exporter/tasks/preflight.yml @@ -24,3 +24,34 @@ ansible.builtin.assert: that: - "':' in blackbox_exporter_web_listen_address" + +- name: Discover latest version + ansible.builtin.set_fact: + blackbox_exporter_version: "{{ (lookup('url', 'https://api.github.com/repos/prometheus/blackbox_exporter/releases/latest', headers=_github_api_headers, + split_lines=False) | from_json).get('tag_name') | replace('v', '') }}" + run_once: true + until: blackbox_exporter_version is version('0.0.0', '>=') + retries: 10 + when: + - blackbox_exporter_version == "latest" + - blackbox_exporter_binary_local_dir | length == 0 + - not blackbox_exporter_skip_install + +- name: Get blackbox_exporter binary checksum + when: + - blackbox_exporter_binary_local_dir | length == 0 + - not blackbox_exporter_skip_install + block: + - name: Get checksum list from github + ansible.builtin.set_fact: + __blackbox_exporter_checksums: "{{ lookup('url', blackbox_exporter_checksums_url, headers=_github_api_headers, wantlist=True) | list }}" + run_once: true + until: __blackbox_exporter_checksums is search('linux-' + go_arch + '.tar.gz') + retries: 10 + + - name: "Get checksum for {{ go_arch }}" + ansible.builtin.set_fact: + __blackbox_exporter_checksum: "{{ item.split(' ')[0] }}" + with_items: "{{ __blackbox_exporter_checksums }}" + when: + - "('linux-' + go_arch + '.tar.gz') in item" diff --git a/roles/blackbox_exporter/vars/main.yml b/roles/blackbox_exporter/vars/main.yml index a16d1e549..5a78bf2a3 100644 --- a/roles/blackbox_exporter/vars/main.yml +++ b/roles/blackbox_exporter/vars/main.yml @@ -5,4 +5,7 @@ go_arch_map: aarch64: 'arm64' armv7l: 'armv7' armv6l: 'armv6' + +go_arch: "{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}" _blackbox_exporter_repo: "prometheus/blackbox_exporter" +_github_api_headers: "{{ {'GITHUB_TOKEN': lookup('ansible.builtin.env', 'GITHUB_TOKEN')} if (lookup('ansible.builtin.env', 'GITHUB_TOKEN')) else {} }}" diff --git a/roles/snmp_exporter/defaults/main.yml b/roles/snmp_exporter/defaults/main.yml index 221174f67..83aabf7aa 100644 --- a/roles/snmp_exporter/defaults/main.yml +++ b/roles/snmp_exporter/defaults/main.yml @@ -1,5 +1,6 @@ --- snmp_exporter_version: 0.23.0 +snmp_exporter_binary_local_dir: "" snmp_exporter_binary_url: "https://github.com/{{ _snmp_exporter_repo }}/releases/download/v{{ snmp_exporter_version }}/\ snmp_exporter-{{ snmp_exporter_version }}.linux-{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}.tar.gz" snmp_exporter_checksums_url: "https://github.com/{{ _snmp_exporter_repo }}/releases/download/v{{ snmp_exporter_version }}/sha256sums.txt" @@ -9,3 +10,5 @@ snmp_exporter_log_level: info # If this is empty, role will download snmp.yml file from https://github.com/prometheus/snmp_exporter. snmp_exporter_config_file: "" + +snmp_exporter_binary_install_dir: "/usr/local/bin" diff --git a/roles/snmp_exporter/meta/argument_specs.yml b/roles/snmp_exporter/meta/argument_specs.yml index 23e5287ad..be9ea3dce 100644 --- a/roles/snmp_exporter/meta/argument_specs.yml +++ b/roles/snmp_exporter/meta/argument_specs.yml @@ -9,12 +9,17 @@ argument_specs: - "Prometheus Community" options: snmp_exporter_version: - description: "SNMP exporter package version" + description: "SNMP exporter package version. Also accepts latest as parameter." default: "0.23.0" snmp_exporter_skip_install: description: "SNMP exporter installation tasks gets skipped when set to true." type: bool default: false + snmp_exporter_binary_local_dir: + description: + - "Enables the use of local packages instead of those distributed on github." + - "The parameter masnmp set to a directory where the C(snmp_exporter) binary is stored on the host where ansible is run." + - "This overrides the I(snmp_exporter_version) parameter" snmp_exporter_binary_url: description: "URL of the snmp exporter binaries .tar.gz file" default: "https://github.com/{{ _snmp_exporter_repo }}/releases/download/v{{ snmp_exporter_version }}/snmp_exporter-{{ snmp_exporter_version }}.linux-{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}.tar.gz" @@ -31,3 +36,8 @@ argument_specs: description: - "If this is empty, role will download snmp.yml file from U(https://github.com/prometheus/snmp_exporter)." - "Otherwise this should contain path to file with custom snmp exporter configuration" + snmp_exporter_binary_install_dir: + description: + - "I(Advanced)" + - "Directory to install snmp_exporter binary" + default: "/usr/local/bin" diff --git a/roles/snmp_exporter/tasks/install.yml b/roles/snmp_exporter/tasks/install.yml index a67690484..ecf03d795 100644 --- a/roles/snmp_exporter/tasks/install.yml +++ b/roles/snmp_exporter/tasks/install.yml @@ -1,37 +1,54 @@ --- -- name: Download snmp_exporter binary to local folder - become: false - ansible.builtin.get_url: - url: "{{ snmp_exporter_binary_url }}" - dest: "/tmp" - checksum: "sha256:{{ snmp_exporter_checksum }}" - mode: 0644 - register: _download_binary - until: _download_binary is success - retries: 5 - delay: 2 - delegate_to: localhost - check_mode: false - when: not snmp_exporter_skip_install +- name: Get binary + when: + - snmp_exporter_binary_local_dir | length == 0 + - not snmp_exporter_skip_install + block: -- name: Unpack snmp_exporter binary - become: false - ansible.builtin.unarchive: - src: "/tmp/snmp_exporter-{{ snmp_exporter_version }}.linux-{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}.tar.gz" - dest: "/tmp" - creates: "/tmp/snmp_exporter-{{ snmp_exporter_version }}.linux-{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}/snmp_exporter" - delegate_to: localhost - check_mode: false - when: not snmp_exporter_skip_install + - name: Download snmp_exporter binary to local folder + become: false + ansible.builtin.get_url: + url: "{{ snmp_exporter_binary_url }}" + dest: "/tmp/snmp_exporter-{{ snmp_exporter_version }}.linux-{{ go_arch }}.tar.gz" + checksum: "sha256:{{ __snmp_exporter_checksum }}" + mode: '0644' + register: _download_binary + until: _download_binary is succeeded + retries: 5 + delay: 2 + delegate_to: localhost + check_mode: false -- name: Propagate SNMP Exporter binaries + - name: Unpack snmp_exporter binary + become: false + ansible.builtin.unarchive: + src: "/tmp/snmp_exporter-{{ snmp_exporter_version }}.linux-{{ go_arch }}.tar.gz" + dest: "/tmp" + creates: "/tmp/snmp_exporter-{{ snmp_exporter_version }}.linux-{{ go_arch }}/snmp_exporter" + delegate_to: localhost + check_mode: false + + - name: Propagate snmp_exporter binaries + ansible.builtin.copy: + src: "/tmp/snmp_exporter-{{ snmp_exporter_version }}.linux-{{ go_arch }}/snmp_exporter" + dest: "{{ snmp_exporter_binary_install_dir }}/snmp_exporter" + mode: 0755 + owner: root + group: root + notify: restart snmp_exporter + when: not ansible_check_mode + +- name: Propagate locally distributed snmp_exporter binary ansible.builtin.copy: - src: "/tmp/snmp_exporter-{{ snmp_exporter_version }}.linux-{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}/snmp_exporter" - dest: "/usr/local/bin/snmp_exporter" + src: "{{ snmp_exporter_binary_local_dir }}/snmp_exporter" + dest: "{{ snmp_exporter_binary_install_dir }}/snmp_exporter" mode: 0755 - when: not snmp_exporter_skip_install - notify: - - restart snmp exporter + owner: root + group: root + when: + - snmp_exporter_binary_local_dir | length > 0 + - not snmp_exporter_skip_install + notify: restart snmp_exporter - name: Create configuration directory ansible.builtin.file: diff --git a/roles/snmp_exporter/tasks/preflight.yml b/roles/snmp_exporter/tasks/preflight.yml index f6ffdeac9..d72310c32 100644 --- a/roles/snmp_exporter/tasks/preflight.yml +++ b/roles/snmp_exporter/tasks/preflight.yml @@ -1,9 +1,31 @@ --- -- name: "Get checksum for snmp exporter" +- name: Discover latest version ansible.builtin.set_fact: - snmp_exporter_checksum: "{{ item.split(' ')[0] }}" - with_items: - - "{{ lookup('url', snmp_exporter_checksums_url, headers=_github_api_headers, wantlist=True) | list }}" + snmp_exporter_version: "{{ (lookup('url', 'https://api.github.com/repos/prometheus/snmp_exporter/releases/latest', headers=_github_api_headers, + split_lines=False) | from_json).get('tag_name') | replace('v', '') }}" + run_once: true + until: snmp_exporter_version is version('0.0.0', '>=') + retries: 10 when: - - "('linux-' + (go_arch_map[ansible_architecture] | default(ansible_architecture)) + '.tar.gz') in item" + - snmp_exporter_version == "latest" + - snmp_exporter_binary_local_dir | length == 0 - not snmp_exporter_skip_install + +- name: Get snmp_exporter binary checksum + when: + - snmp_exporter_binary_local_dir | length == 0 + - not snmp_exporter_skip_install + block: + - name: Get checksum list from github + ansible.builtin.set_fact: + __snmp_exporter_checksums: "{{ lookup('url', snmp_exporter_checksums_url, headers=_github_api_headers, wantlist=True) | list }}" + run_once: true + until: __snmp_exporter_checksums is search('linux-' + go_arch + '.tar.gz') + retries: 10 + + - name: "Get checksum for {{ go_arch }}" + ansible.builtin.set_fact: + __snmp_exporter_checksum: "{{ item.split(' ')[0] }}" + with_items: "{{ __snmp_exporter_checksums }}" + when: + - "('linux-' + go_arch + '.tar.gz') in item" diff --git a/roles/snmp_exporter/vars/main.yml b/roles/snmp_exporter/vars/main.yml index bd456ebcf..9de953784 100644 --- a/roles/snmp_exporter/vars/main.yml +++ b/roles/snmp_exporter/vars/main.yml @@ -5,5 +5,7 @@ go_arch_map: aarch64: 'arm64' armv7l: 'armv7' armv6l: 'armv6' + +go_arch: "{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}" _snmp_exporter_repo: "prometheus/snmp_exporter" _github_api_headers: "{{ {'GITHUB_TOKEN': lookup('ansible.builtin.env', 'GITHUB_TOKEN')} if (lookup('ansible.builtin.env', 'GITHUB_TOKEN')) else {} }}"