diff --git a/README.md b/README.md index 6a261fda681572eec68b158b2d369d1e826715a8..17e37574c64d6e175afee55fb9ca4460d79d7df1 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,12 @@ All variables which can be overridden are stored in [defaults/main.yml](defaults | `node_exporter_web_listen_address` | "0.0.0.0:9100" | Address on which node exporter will listen | | `node_exporter_enabled_collectors` | [ systemd, textfile ] | List of additionally enabled collectors. It adds collectors to [those enabled by default](https://github.com/prometheus/node_exporter#enabled-by-default) | | `node_exporter_disabled_collectors` | [] | List of disabled collectors. By default node_exporter disables collectors listed [here](https://github.com/prometheus/node_exporter#disabled-by-default). | -| `node_exporter_textfile_dir` | "/var/lib/node_exporter" | Directory used by the [Textfile Collector](https://github.com/prometheus/node_exporter#textfile-collector). To get permissions to write metrics in this directory, users must be in `node-exp` system group. +| `node_exporter_textfile_dir` | "/var/lib/node_exporter" | Directory used by the [Textfile Collector](https://github.com/prometheus/node_exporter#textfile-collector). To get permissions to write metrics in this directory, users must be in `node-exp` system group. | +| `node_exporter_textfile_collectors` | [] | List of textfile collectors which should be copied and crontab setup for them. | ## Example -### Playbook +### Basic playbook Use it in a playbook as follows: ```yaml @@ -40,6 +41,34 @@ Use it in a playbook as follows: - cloudalchemy.node-exporter ``` +### Advanced playbook +Following playbook sets up few more advanced features of this role. Mostly: +- Every role run checks and tries to update node_exporter binary to latest available version +- node_exporter is run as `root` user, which allows to use `systemd` collector +- `systemd` collector is enabled +- enables cron job running two textfile collectors: [`yum.sh`](https://github.com/prometheus-community/node-exporter-textfile-collector-scripts/blob/master/yum.sh) and [`md_info_detail.sh`](https://github.com/prometheus-community/node-exporter-textfile-collector-scripts/blob/master/md_info_detail.sh) Textfile collector is also copied from deployer host with path specified in `src`. + +```yaml +- hosts: all + roles: + - cloudalchemy.node-exporter + vars: + node_exporter_system_group: "root" + node_exporter_system_user: "root" + node_exporter_enabled_collectors: + - systemd + node_exporter_textfile_collectors: + - src: "/tmp/md_info_detail.sh" + special_time: "hourly" + - src: "/tmp/yum.sh" + user: node-exp + minute: "*" + hour: "*" + day: "*" + month: "*" + weekday: "*" +``` + ### Demo site We provide demo site for full monitoring solution based on prometheus and grafana. Repository with code and links to running instances is [available on github](https://github.com/cloudalchemy/demo-site) and site is hosted on [DigitalOcean](https://digitalocean.com). diff --git a/defaults/main.yml b/defaults/main.yml index f6f549aa7f676f7813c91d5485374c5f97055d2e..dc2b75f33b343e0de98f6f0b4a4e2a7b5a450bb2 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -4,6 +4,17 @@ node_exporter_binary_local_dir: "" node_exporter_web_listen_address: "0.0.0.0:9100" node_exporter_textfile_dir: "/var/lib/node_exporter" +node_exporter_textfile_collectors: [] +# node_exporter_textfile_collectors: +# - src: "/tmp/apt.sh" +# user: root +# calendar: "" +# active_sec: "" +# boot_sec: "" +# startup_sec: "" +# unit_active_sec: "" +# unit_inactive_sec: "" + node_exporter_enabled_collectors: - systemd diff --git a/handlers/main.yml b/handlers/main.yml index 25551ee0142529a1d5b60469ae651dcc09b9148d..2c4240c8d2970c48fca4dafffa3119c945b5d37a 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -5,3 +5,11 @@ daemon_reload: true name: node_exporter state: restarted + +- name: reload cron + become: true + systemd: + daemon_reload: true + name: "textfile-collector-{{ item.src | basename }}.timer" + state: restarted + with_items: "{{ node_exporter_textfile_collectors }}" diff --git a/molecule/alternative/playbook.yml b/molecule/alternative/playbook.yml index ce51111dba0ff735e4ce3f03f834c55c625a8647..22c455e17e7afea65d912b07229696c833671128 100644 --- a/molecule/alternative/playbook.yml +++ b/molecule/alternative/playbook.yml @@ -11,3 +11,8 @@ - entropy node_exporter_disabled_collectors: - diskstats + node_exporter_textfile_collectors: + - src: "/tmp/apt.sh" + user: root + calendar: "1h 30min" + boot_sec: 90 diff --git a/molecule/alternative/prepare.yml b/molecule/alternative/prepare.yml index 2f75da1308b8821da9f6477f90c0f87e9e961b68..742234c4607ca18c984f2f0a58bc2e52862b27ef 100644 --- a/molecule/alternative/prepare.yml +++ b/molecule/alternative/prepare.yml @@ -1,5 +1,5 @@ --- -- name: Prepare +- name: Prepare localhost hosts: localhost gather_facts: false vars: @@ -35,3 +35,19 @@ state: link run_once: true check_mode: false + + - name: get collector scripts + become: false + get_url: + url: "{{ item }}" + dest: "/tmp/{{ item.split('/')[-1] }}" + with_items: + - https://raw.githubusercontent.com/prometheus-community/node-exporter-textfile-collector-scripts/master/apt.sh + +- name: Prepare instances + hosts: all + tasks: + - name: Install cron + package: + name: "{{ 'cronie' if (ansible_os_family | lower == 'redhat') else 'cron' }}" + state: present diff --git a/molecule/alternative/tests/test_alternative.py b/molecule/alternative/tests/test_alternative.py index 87cfc15ad5157498808b7ddd9c23f4a55be65a12..1ea16feb27d4369714279e23bba69c64bde37ddd 100644 --- a/molecule/alternative/tests/test_alternative.py +++ b/molecule/alternative/tests/test_alternative.py @@ -5,13 +5,30 @@ testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') +def test_files(host): + files = [ + "/usr/local/bin/md_info_detail.sh", + "/usr/local/bin/apt.sh" + "/etc/systemd/system/textfile-collector-apt.sh.service" + "/etc/systemd/system/textfile-collector-apt.sh.timer" + "/etc/systemd/system/textfile-collector-md_info_detail.sh.service" + "/etc/systemd/system/textfile-collector-md_info_detail.sh.timer" + ] + for file in files: + f = host.file(file) + assert f.exists + assert f.is_file + assert oct(f.mode) == '0o755' + + def test_directories(host): dirs = [ "/var/lib/node_exporter" ] for dir in dirs: d = host.file(dir) - assert not d.exists + assert d.is_directory + assert d.exists def test_service(host): diff --git a/molecule/default/playbook.yml b/molecule/default/playbook.yml index 1e92855e9700d3ef1023559b2ed1afde16dbf704..36af894827a8fc9fbce382875b3822637652bc8d 100644 --- a/molecule/default/playbook.yml +++ b/molecule/default/playbook.yml @@ -5,3 +5,4 @@ - ansible-node-exporter vars: node_exporter_web_listen_address: "127.0.0.1:9100" + node_exporter_textfile_dir: "" diff --git a/molecule/default/tests/test_default.py b/molecule/default/tests/test_default.py index 779758880094014ca59e8270c2ca5e31323a8ec4..ef1a546f459da33b52a39509be31b23cd07f4002 100644 --- a/molecule/default/tests/test_default.py +++ b/molecule/default/tests/test_default.py @@ -11,8 +11,7 @@ def test_directories(host): ] for dir in dirs: d = host.file(dir) - assert d.is_directory - assert d.exists + assert not d.exists def test_files(host): diff --git a/tasks/configure.yml b/tasks/configure.yml index 9e9f9bce9b50bebe29cce88b34295ffdc4a7d65f..ec9d8263690711be5b4585f5eaae410f7ffa730c 100644 --- a/tasks/configure.yml +++ b/tasks/configure.yml @@ -8,16 +8,6 @@ mode: 0644 notify: restart node_exporter -- name: Create textfile collector dir - file: - path: "{{ node_exporter_textfile_dir }}" - state: directory - owner: "{{ _node_exporter_system_user }}" - group: "{{ _node_exporter_system_group }}" - recurse: true - mode: u+rwX,g+rwX,o=rX - when: node_exporter_textfile_dir | length > 0 - - name: Allow Node Exporter port in SELinux on RedHat OS family seport: ports: "{{ node_exporter_web_listen_address.split(':')[-1] }}" @@ -27,3 +17,45 @@ when: - ansible_version.full is version_compare('2.4', '>=') - ansible_selinux.status == "enabled" + +- block: + - name: Create textfile collector dir + file: + path: "{{ node_exporter_textfile_dir }}" + state: directory + owner: "{{ _node_exporter_system_user }}" + group: "{{ _node_exporter_system_group }}" + recurse: true + mode: u+rwX,g+rwX,o=rX + + - name: Download textfile collector scripts + copy: + src: "{{ item.src }}" + dest: "{{ _node_exporter_binary_install_dir }}/{{ item.src | basename }}" + owner: root + group: root + mode: "0755" + with_items: "{{ node_exporter_textfile_collectors }}" + + - name: Setup textfile collector script systemd cron service + template: + src: "cron.service.j2" + dest: "/etc/systemd/systemd/textfile-collector-{{ item.src | basename }}.service" + with_items: "{{ node_exporter_textfile_collectors }}" + notify: reload cron + + - name: Setup textfile collector script systemd cron timer + template: + src: "cron.timer.j2" + dest: "/etc/systemd/systemd/textfile-collector-{{ item.src | basename }}.timer" + with_items: "{{ node_exporter_textfile_collectors }}" + notify: reload cron + + - name: Enable textfile collector + systemd: + daemon_reload: true + name: "textfile-collector-{{ item.src | basename }}.timer" + enabled: true + state: started + with_items: "{{ node_exporter_textfile_collectors }}" + when: node_exporter_textfile_dir | length > 0 diff --git a/tasks/preflight.yml b/tasks/preflight.yml index 79fff42d3eb6fa8ea4d319a73076d3baf2b4dec4..ea2ca87f5feda5c1c6dac43a3d89f64e35569478 100644 --- a/tasks/preflight.yml +++ b/tasks/preflight.yml @@ -27,6 +27,23 @@ - "item not in node_exporter_enabled_collectors" with_items: "{{ node_exporter_disabled_collectors }}" +- block: + - name: Check for "/etc/crontab" + stat: + path: "/etc/crontab" + register: __node_exportert_etc_crontab + + - name: Assert /etc/crontab exists when using textfile collector scripts + assert: + that: + __node_exportert_etc_crontab.stat.exists + + - name: Assert node_exporter_textfile_dir is not empty when using collector scripts + assert: + that: + - node_exporter_textfile_dir | length != 0 + when: node_exporter_textfile_collectors | length != 0 + - name: Check if node_exporter is installed stat: path: "{{ _node_exporter_binary_install_dir }}/node_exporter" diff --git a/templates/cron.service.j2 b/templates/cron.service.j2 new file mode 100644 index 0000000000000000000000000000000000000000..9830a5fabe44dcffbf269566ac4d8235fb9e1705 --- /dev/null +++ b/templates/cron.service.j2 @@ -0,0 +1,9 @@ +[Unit] +Description=Run Textfile Collector {{ item.src | basename }} + +[Service] +User={{ item.user | default("root") }} +ExecStart=/bin/sh -c '\ + TEMP=$(mktemp -q) && \ + {{ _node_exporter_binary_install_dir }}/{{ item.src | basename }} > $TEMP && \ + mv $TEMP {{ node_exporter_textfile_dir }}/{{ item.src | basename }}.prom' diff --git a/templates/cron.timer.j2 b/templates/cron.timer.j2 new file mode 100644 index 0000000000000000000000000000000000000000..52dbdd552ad405f4a7cdac923443dbc69b0d88d7 --- /dev/null +++ b/templates/cron.timer.j2 @@ -0,0 +1,14 @@ +[Unit] +Description=Textfile Collector {{ item.src | basename }} timer + +[Timer] +Unit=textfile-collector-{{ item.src | basename }}.service +OnCalendar={{ item.calendar }} +OnBootSec={{ item.boot_sec }} +OnActiveSec={{ item.active_sec }} +OnStartupSec={{ item.startup_sec }} +OnUnitActiveSec={{ item.unit_active_sec }} +OnUnitInactiveSec={{ item.unit_inactive_sec }} + +[Install] +WantedBy=multi-user.target