diff --git a/README.md b/README.md index e9151cd..181aa68 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ - [ipmi_exporter](roles/ipmi_exporter/README.md) - [mount_device](roles/mount_device/README.md) - [prometheus](roles/prometheus/README.md) +- [smartctl_exporter](roles/smartctl_exporter/README.md) - [ufw](roles/ufw/README.md) - [wg_hub](roles/wg_hub/README.md) - [wg_spoke](roles/wg_spoke/README.md) \ No newline at end of file diff --git a/galaxy.yml b/galaxy.yml index 409ec6a..4bb7cfd 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: genlab name: common -version: 0.10.0 +version: 0.11.0 readme: README.md authors: - Alexander Gorelyshev (corvus-migratorius@proton.me) diff --git a/roles/smartctl_exporter/.gitignore b/roles/smartctl_exporter/.gitignore new file mode 100644 index 0000000..8cd0df3 --- /dev/null +++ b/roles/smartctl_exporter/.gitignore @@ -0,0 +1,2 @@ +.vscode +.idea \ No newline at end of file diff --git a/roles/smartctl_exporter/README.md b/roles/smartctl_exporter/README.md new file mode 100644 index 0000000..1c1de90 --- /dev/null +++ b/roles/smartctl_exporter/README.md @@ -0,0 +1,56 @@ +genlab.smartctl-exporter +========= + +```smartctl``` is a command-line utility used to control and monitor the Self-Monitoring, Analysis and Reporting Technology (SMART) system in hard disk drives (HDDs) and solid-state drives (SSDs). ```smartctl-exporter``` exports ```smartctl``` statistics to Prometheus. + +Requirements +------------ + +smartctl + +Role Variables +-------------- +The exporter will scan the system for available devices if no ```--smartctl.device``` flags are used. The format of web.config file id described [here](https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md). If ```smartctl_exp_source_web_config_dir``` is defined, role searches for ```web_smartctl.conf``` file and copy it to target host to ```smartctl_exp_web_config_dir``` directory +```yaml +--- +smartctl_exp_port: "localhost:9633" # Addresses on which to expose metrics and web interface. Repeatable for multiple addresses. +smartctl_exp_version: "0.14.0" # exporter version to install +smartctl_exp_dir: "/etc/exporters" # where to download and unarchive expoter +smartctl_exp_web_config_dir: "/etc/exporters/config" # Path to configuration file that can enable TLS or authentication +smartctl_exp_interval: "60s" # The interval between smartctl polls +smartctl_exp_rescan: "10m" # The interval between rescanning for new/disappeared devices. If the interval is smaller than 1s no rescanning takes place. If any devices are configured with smartctl.device also no rescanning takes place. +smartctl_exp_devices: [] # The device to monitor (repeatable) +smartctl_exp_device_exclude: "" #Regexp of devices to exclude from automatic scanning. (mutually exclusive to device-include) +smartctl_exp_device_include: "" # Regexp of devices to include in automatic scanning. (mutually exclusive to device-exclude) +smartctl_exp_web_telemetry_path: "/metrics" # Path under which to expose metrics +smartctl_exp_log_level: "info" # Only log messages with the given severity or above. One of: [debug, info, warn, error] +smartctl_exp_log_format: "logfmt" # Output format of log messages. One of: [logfmt, json] +smartctl_exp_args: # --version --web.systemd-socket + +smartctl_exp_source_web_config_dir: "" +``` +Dependencies +------------ + +None + +Example Playbook +---------------- + +```yaml +roles: +- role: genlab.smartctl_exporter + smartctl_exp_version: "0.14.0" + smartctl_exp_dir: "/etc/exporters" + smartctl_exp_config_dir: "/etc/exporters/config" +``` + +License +------- + +BSD + +Author Information +------------------ + +corvus-migratorius@proton.me diff --git a/roles/smartctl_exporter/defaults/main.yml b/roles/smartctl_exporter/defaults/main.yml new file mode 100644 index 0000000..8c146b9 --- /dev/null +++ b/roles/smartctl_exporter/defaults/main.yml @@ -0,0 +1,14 @@ +--- +smartctl_exporter_web_listen_address: "localhost:9633" +smartctl_exporter_args: "" +smartctl_exporter_version: "0.14.0" +smartctl_exporter_dir: "/etc/exporters" +smartctl_exporter_web_config_dir: "/etc/exporters/config" +smartctl_exporter_interval: "60s" +smartctl_exporter_rescan: "10m" +smartctl_exporter_devices: [] +smartctl_exporter_device_exclude: "" +smartctl_exporter_device_include: "" +smartctl_exporter_web_telemetry_path: "/metrics" +smartctl_exporter_log_level: "info" +smartctl_exporter_log_format: "logfmt" diff --git a/roles/smartctl_exporter/handlers/main.yml b/roles/smartctl_exporter/handlers/main.yml new file mode 100644 index 0000000..f9173f1 --- /dev/null +++ b/roles/smartctl_exporter/handlers/main.yml @@ -0,0 +1,7 @@ +--- +- name: "(Re)start and enable smartctl_exporter" + ansible.builtin.systemd_service: + name: smartctl_exporter.service + state: restarted + enabled: true + daemon_reload: true diff --git a/roles/smartctl_exporter/meta/main.yml b/roles/smartctl_exporter/meta/main.yml new file mode 100644 index 0000000..cde1c90 --- /dev/null +++ b/roles/smartctl_exporter/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + role_name: "smartctl_exporter" + namespace: genlab + author: "Alexander Gorelyshev" + company: "Genlab, LLC" + description: "" + license: "MIT" + min_ansible_version: "2.1" + + platforms: + - name: "Ubuntu" + versions: ["focal", "jammy", "noble"] + + galaxy_tags: [] + +dependencies: [] diff --git a/roles/smartctl_exporter/molecule/default/converge.yml b/roles/smartctl_exporter/molecule/default/converge.yml new file mode 100644 index 0000000..fcbdf59 --- /dev/null +++ b/roles/smartctl_exporter/molecule/default/converge.yml @@ -0,0 +1,7 @@ +--- +- name: Converge + hosts: all + roles: + - role: genlab.common.smartctl_exporter + smartctl_exporter_dir: "/etc/exporters" + smartctl_exp_config_dir: "/etc/exporters/config" diff --git a/roles/smartctl_exporter/molecule/default/molecule.yml b/roles/smartctl_exporter/molecule/default/molecule.yml new file mode 100644 index 0000000..d82158e --- /dev/null +++ b/roles/smartctl_exporter/molecule/default/molecule.yml @@ -0,0 +1,27 @@ +--- +dependency: + name: galaxy + +driver: + name: docker + +platforms: + - name: ubuntu + image: geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2404}-ansible:latest + pre_build_image: true + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host + privileged: true + +provisioner: + name: ansible + +verifier: + name: ansible + +lint: | + set -e + yamllint . + ansible-lint . diff --git a/roles/smartctl_exporter/molecule/default/verify.yml b/roles/smartctl_exporter/molecule/default/verify.yml new file mode 100644 index 0000000..de66787 --- /dev/null +++ b/roles/smartctl_exporter/molecule/default/verify.yml @@ -0,0 +1,37 @@ +--- +- name: Verify + hosts: all + gather_facts: false + any_errors_fatal: true + + tasks: + - name: "Include default vars" + ansible.builtin.include_vars: + dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults/" + extensions: ['yml'] + + - name: "Check if smartctl_exporter is installed" + changed_when: false + ansible.builtin.command: "smartctl_exporter --version" + register: smartctl_exporter_installed_version + + - name: "Check smartctl_exporter version" + ansible.builtin.assert: + that: "smartctl_exporter_installed_version.stderr is regex('{{ smartctl_exporter_version }}')" + success_msg: "smartctl_exporter version {{ smartctl_exporter_version }} is installed and working" + fail_msg: "smartctl_exporter version {{ smartctl_exporter_version }} is not installed or not working correctly" + + # kics-scan ignore-block + - name: "Check if /metrics endpoint is reachable" + ansible.builtin.uri: + url: "http://{{ smartctl_exporter_web_listen_address }}/metrics" + return_content: true + status_code: 200 + timeout: 5 + register: smartctl_exporter_metrics_check + + - name: "Fail if /metrics doesn't contain smartctl_exporter_build_info line" + ansible.builtin.assert: + that: "'smartctl_exporter_build_info' in smartctl_exporter_metrics_check.content" + fail_msg: "smartctl_exporter /metrics endpoint doesn't contain smartctl_exporter_build_info line!" + success_msg: "smartctl_exporter /metrics endpoint contains smartctl_exporter_build_info line!" diff --git a/roles/smartctl_exporter/tasks/configure.yml b/roles/smartctl_exporter/tasks/configure.yml new file mode 100644 index 0000000..61ef10c --- /dev/null +++ b/roles/smartctl_exporter/tasks/configure.yml @@ -0,0 +1,10 @@ +--- +- name: "Upload smartctl_exporter local configure file" + notify: "(Re)start and enable smartctl_exporter" + when: smartctl_exp_source_web_config_dir is defined and smartctl_exp_source_web_config_dir | length > 0 + ansible.builtin.template: + src: "{{ smartctl_exp_source_web_config_dir }}/web_smartctl.conf" + dest: "{{ smartctl_exporter_web_config_dir }}/web_smartctl.conf" + owner: root + group: root + mode: '0640' diff --git a/roles/smartctl_exporter/tasks/install.yml b/roles/smartctl_exporter/tasks/install.yml new file mode 100644 index 0000000..3ddaafc --- /dev/null +++ b/roles/smartctl_exporter/tasks/install.yml @@ -0,0 +1,51 @@ +--- +- name: "Install smartctl_exporter from binary" + block: + - name: "Check smartctl_exporter version" + changed_when: false + ansible.builtin.command: + cmd: "smartctl_exporter --version" + register: smartctl_exporter_ver + + - name: "Assert version correctness" + ansible.builtin.assert: + that: "smartctl_exporter_ver.stderr is regex('{{ smartctl_exporter_version }}')" + success_msg: "smartctl_exporter version {{ smartctl_exporter_version }} is installed and working" + fail_msg: "smartctl_exporter version {{ smartctl_exporter_version }} is not installed or not working correctly" + + rescue: + - name: "Create smartctl_exporter directories" + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: root + group: root + mode: "0755" + with_items: + - "{{ smartctl_exporter_dir }}" + - "{{ smartctl_exp_config_dir }}" + + - name: "Unarchive smartctl_exporter tar file" + notify: "(Re)start and enable smartctl_exporter" + ansible.builtin.unarchive: + src: "https://github.com/prometheus-community/smartctl_exporter/releases/\ + download/v{{ smartctl_exporter_version }}/smartctl_exporter-{{ smartctl_exporter_version }}.linux-amd64.tar.gz" + dest: "{{ smartctl_exporter_dir }}" + remote_src: true + + - name: "Move smartctl_exporter binary" + ansible.builtin.copy: + src: "{{ smartctl_exporter_dir }}/smartctl_exporter-{{ smartctl_exporter_version }}.linux-amd64/smartctl_exporter" + dest: "/usr/local/bin/smartctl_exporter" + mode: "0755" + owner: root + group: root + remote_src: true + +- name: Create systemd service file + ansible.builtin.template: + src: smartctl_exporter.service.j2 + dest: /etc/systemd/system/smartctl_exporter.service + owner: root + group: root + mode: '0644' diff --git a/roles/smartctl_exporter/tasks/main.yml b/roles/smartctl_exporter/tasks/main.yml new file mode 100644 index 0000000..76dd507 --- /dev/null +++ b/roles/smartctl_exporter/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: "Include installation tasks" + ansible.builtin.include_tasks: "install.yml" + +- name: "Including configuration tasks" + ansible.builtin.include_tasks: "configure.yml" diff --git a/roles/smartctl_exporter/templates/smartctl_exporter.service.j2 b/roles/smartctl_exporter/templates/smartctl_exporter.service.j2 new file mode 100644 index 0000000..abe2a5b --- /dev/null +++ b/roles/smartctl_exporter/templates/smartctl_exporter.service.j2 @@ -0,0 +1,46 @@ +[Unit] +Description=Smartctl Exporter +Documentation=https://github.com/prometheus-community/smartctl_exporter +After=network.target +StartLimitIntervalSec=120 +StartLimitBurst=5 + +[Service] +Type=simple +User=root +Group=root +ExecStart=/usr/local/bin/smartctl_exporter \ + --web.listen-address={{ smartctl_exporter_web_listen_address }} \ + --smartctl.interval={{ smartctl_exporter_interval }} \ + --smartctl.rescan={{ smartctl_exporter_rescan }} \ +{% if smartctl_exporter_devices is defined and smartctl_exporter_devices | length > 0 %} + {% for device in smartctl_exporter_devices %} + --smartctl.device={{ device }} \ + {% endfor %} +{% endif %} + --smartctl.device-exclude={{ smartctl_exporter_device_exclude }} \ + --smartctl.device-include={{ smartctl_exporter_device_include }} \ + --web.telemetry-path={{ smartctl_exporter_web_telemetry_path }} \ + --log.level={{ smartctl_exporter_log_level }} \ + --log.format={{ smartctl_exporter_log_format }} \ +{% if smartctl_exporter_args is defined and smartctl_exporter_args | length > 0 %} + {{ smartctl_exporter_args }} \ +{% endif %} +{% if smartctl_exp_source_web_config_dir is defined and smartctl_exp_source_web_config_dir | length > 0 %} \ + --web.config.file={{ smartctl_exporter_web_config_dir }}/web_smartctl.conf +{% endif %} + +SyslogIdentifier=smartctl_exporter +Restart=on-failure +RestartSec=5 + +ProtectHome=yes +NoNewPrivileges=yes +ProtectSystem=strict +ProtectControlGroups=true +ProtectKernelModules=true +ProtectKernelTunables=yes +ProtectSystem=full + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/smartctl_exporter/vars/main.yml b/roles/smartctl_exporter/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/smartctl_exporter/vars/main.yml @@ -0,0 +1 @@ +---