From bdc6227432111b5c9be1e46f9d09986e55ef82dd Mon Sep 17 00:00:00 2001 From: Jeltz Date: Sun, 6 Jul 2025 19:40:12 +0200 Subject: [PATCH] Initial commit --- ansible.cfg | 14 ++ backups.yml | 43 ++++++ group_vars/all.yml | 8 ++ host_vars/carlosgon.yml | 3 + host_vars/dodecagon.yml | 3 + host_vars/dragon.yml | 3 + host_vars/glucagon.yml | 3 + host_vars/harpagon.yml | 3 + host_vars/hendecagon.yml | 3 + host_vars/memoragon.yml | 3 + host_vars/patagon.yml | 3 + host_vars/ronderu.yml | 3 + host_vars/saigon.yml | 3 + hosts | 13 ++ monitoring.yml | 13 ++ requirements.yml | 4 + roles/backports/tasks/main.yml | 17 +++ roles/backports/vars/main.yml | 4 + roles/borgmatic/defaults/main.yml | 10 ++ .../__pycache__/borgmatic.cpython-312.pyc | Bin 0 -> 883 bytes roles/borgmatic/filter_plugins/borgmatic.py | 11 ++ roles/borgmatic/handlers/main.yml | 5 + roles/borgmatic/tasks/main.yml | 136 ++++++++++++++++++ roles/borgmatic/templates/config.yaml.j2 | 5 + roles/borgmatic/templates/override.conf.j2 | 12 ++ roles/borgmatic/vars/main.yml | 4 + .../defaults/main.yml | 4 + .../handlers/main.yml | 10 ++ roles/prometheus_node_exporter/tasks/main.yml | 69 +++++++++ .../templates/default.j2 | 13 ++ .../templates/override.conf.j2 | 5 + 31 files changed, 430 insertions(+) create mode 100644 ansible.cfg create mode 100755 backups.yml create mode 100644 group_vars/all.yml create mode 100644 host_vars/carlosgon.yml create mode 100644 host_vars/dodecagon.yml create mode 100644 host_vars/dragon.yml create mode 100644 host_vars/glucagon.yml create mode 100644 host_vars/harpagon.yml create mode 100644 host_vars/hendecagon.yml create mode 100644 host_vars/memoragon.yml create mode 100644 host_vars/patagon.yml create mode 100644 host_vars/ronderu.yml create mode 100644 host_vars/saigon.yml create mode 100644 hosts create mode 100755 monitoring.yml create mode 100644 requirements.yml create mode 100644 roles/backports/tasks/main.yml create mode 100644 roles/backports/vars/main.yml create mode 100644 roles/borgmatic/defaults/main.yml create mode 100644 roles/borgmatic/filter_plugins/__pycache__/borgmatic.cpython-312.pyc create mode 100644 roles/borgmatic/filter_plugins/borgmatic.py create mode 100644 roles/borgmatic/handlers/main.yml create mode 100644 roles/borgmatic/tasks/main.yml create mode 100644 roles/borgmatic/templates/config.yaml.j2 create mode 100644 roles/borgmatic/templates/override.conf.j2 create mode 100644 roles/borgmatic/vars/main.yml create mode 100644 roles/prometheus_node_exporter/defaults/main.yml create mode 100644 roles/prometheus_node_exporter/handlers/main.yml create mode 100644 roles/prometheus_node_exporter/tasks/main.yml create mode 100644 roles/prometheus_node_exporter/templates/default.j2 create mode 100644 roles/prometheus_node_exporter/templates/override.conf.j2 diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..43ea50b --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,14 @@ +[defaults] +#ask_vault_pass = True +roles_path = ./roles +inventory = ./hosts +ansible_managed = Ansible managed +remote_user = root +timeout = 60 + +[diff] +always = yes + +[ssh_connection] +pipelining = True +retries = 3 diff --git a/backups.yml b/backups.yml new file mode 100755 index 0000000..b0a3eef --- /dev/null +++ b/backups.yml @@ -0,0 +1,43 @@ +#!/usr/bin/env ansible-playbook +--- +- hosts: + - dodecagon + roles: + - borgmatic + vars: + borg__keep_hourly: 24 + borg__keep_daily: 30 + borg__keep_weekly: 26 + borg__keep_monthly: 36 + borg__backup_dirs: + - /etc + - /home + - /root + - /opt + - /srv + - /var/backups + - /var/log + - /var/local + - /var/lib + - /var/mail + - /var/www + borg__passphrase: UK2mu1faYKQZeBkePbKjxdhuIKBjQriP + borg__targets: + - name: harpagon.infra.federez.net + hostkeys: + - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH1qDEAEJZ0qDRUq4yeHar5LKFTtsvHJIt2a54TBB/Lz + user: borgmatic + path: "/backup/borgmatic/{{ inventory_hostname }}" + - name: memoragon.infra.federez.net + hostkeys: + - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINdqX4I1JyvhC6dySHLnW1IioYk1ZqltFlbDCygozrWx + user: borgmatic + path: "/backup/borgmatic/{{ inventory_hostname }}" + # borg__postgresql: + # - name: all + # username: postgres + borg__mysql: + - name: all + username: root + password: KtQ7wHTecNPCMDISEJ1x +... diff --git a/group_vars/all.yml b/group_vars/all.yml new file mode 100644 index 0000000..1768c2f --- /dev/null +++ b/group_vars/all.yml @@ -0,0 +1,8 @@ +--- +ansible_python_interpreter: /usr/bin/python3 +ansible_host: "{{ inventory_hostname }}.federez.net" +infra__byte_a: "{{ infra__id // 256 }}" +infra__byte_b: "{{ infra__id % 256 }}" +infra__addr_v6: "fd0a:66d3:1c19:42::{{ infra__byte_a }}:{{ infra__byte_b }}" +infra__addr_v4: "10.42.{{ infra__byte_a }}.{{ infra__byte_b }}" +... diff --git a/host_vars/carlosgon.yml b/host_vars/carlosgon.yml new file mode 100644 index 0000000..1b3c770 --- /dev/null +++ b/host_vars/carlosgon.yml @@ -0,0 +1,3 @@ +--- +infra__id: 13 +... diff --git a/host_vars/dodecagon.yml b/host_vars/dodecagon.yml new file mode 100644 index 0000000..c44aa28 --- /dev/null +++ b/host_vars/dodecagon.yml @@ -0,0 +1,3 @@ +--- +infra__id: 4 +... diff --git a/host_vars/dragon.yml b/host_vars/dragon.yml new file mode 100644 index 0000000..254b9b5 --- /dev/null +++ b/host_vars/dragon.yml @@ -0,0 +1,3 @@ +--- +infra__id: 16 +... diff --git a/host_vars/glucagon.yml b/host_vars/glucagon.yml new file mode 100644 index 0000000..4524e19 --- /dev/null +++ b/host_vars/glucagon.yml @@ -0,0 +1,3 @@ +--- +infra__id: 2 +... diff --git a/host_vars/harpagon.yml b/host_vars/harpagon.yml new file mode 100644 index 0000000..8c53928 --- /dev/null +++ b/host_vars/harpagon.yml @@ -0,0 +1,3 @@ +--- +infra__id: 6 +... diff --git a/host_vars/hendecagon.yml b/host_vars/hendecagon.yml new file mode 100644 index 0000000..af4fab1 --- /dev/null +++ b/host_vars/hendecagon.yml @@ -0,0 +1,3 @@ +--- +infra__id: 15 +... diff --git a/host_vars/memoragon.yml b/host_vars/memoragon.yml new file mode 100644 index 0000000..957ef83 --- /dev/null +++ b/host_vars/memoragon.yml @@ -0,0 +1,3 @@ +--- +infra__id: 14 +... diff --git a/host_vars/patagon.yml b/host_vars/patagon.yml new file mode 100644 index 0000000..be849cc --- /dev/null +++ b/host_vars/patagon.yml @@ -0,0 +1,3 @@ +--- +infra__id: 7 +... diff --git a/host_vars/ronderu.yml b/host_vars/ronderu.yml new file mode 100644 index 0000000..fe1d8c7 --- /dev/null +++ b/host_vars/ronderu.yml @@ -0,0 +1,3 @@ +--- +infra__id: 3 +... diff --git a/host_vars/saigon.yml b/host_vars/saigon.yml new file mode 100644 index 0000000..8ea872b --- /dev/null +++ b/host_vars/saigon.yml @@ -0,0 +1,3 @@ +--- +infra__id: 5 +... diff --git a/hosts b/hosts new file mode 100644 index 0000000..a57bc54 --- /dev/null +++ b/hosts @@ -0,0 +1,13 @@ +[debian] +dragon +dodecagon +saigon +harpagon +patagon +carlosgon +memoragon +hendecagon + +[pve] +glucagon +ronderu diff --git a/monitoring.yml b/monitoring.yml new file mode 100755 index 0000000..ae6a8be --- /dev/null +++ b/monitoring.yml @@ -0,0 +1,13 @@ +#!/usr/bin/env ansible-playbook +--- +- hosts: + - debian + - pve + roles: + - prometheus_node_exporter + vars: + prometheus__listen_addrs: + - "{{ infra__addr_v6 }}" + #- "{{ infra__addr_v4 }}" + prometheus__smart_enabled: "{{ 'pve' in group_names }}" +... diff --git a/requirements.yml b/requirements.yml new file mode 100644 index 0000000..bd463a3 --- /dev/null +++ b/requirements.yml @@ -0,0 +1,4 @@ +--- +collections: + - name: community.crypto +... diff --git a/roles/backports/tasks/main.yml b/roles/backports/tasks/main.yml new file mode 100644 index 0000000..4c7f402 --- /dev/null +++ b/roles/backports/tasks/main.yml @@ -0,0 +1,17 @@ +--- +- name: Install python3-debian + ansible.builtin.apt: + name: python3-debian + +- name: Add backports repository + ansible.builtin.apt_repository: + filename: backports + repo: "deb {{ uri }} {{ suite }} {{ components | join(' ') }}" + update_cache: true + vars: + uri: http://deb.debian.org/debian + suite: "{{ ansible_distribution_release }}-backports" + components: + - main + when: "ansible_distribution_release in backports__supported_releases" +... diff --git a/roles/backports/vars/main.yml b/roles/backports/vars/main.yml new file mode 100644 index 0000000..e85b758 --- /dev/null +++ b/roles/backports/vars/main.yml @@ -0,0 +1,4 @@ +--- +backports__supported_releases: + - bullseye +... diff --git a/roles/borgmatic/defaults/main.yml b/roles/borgmatic/defaults/main.yml new file mode 100644 index 0000000..afd7c8f --- /dev/null +++ b/roles/borgmatic/defaults/main.yml @@ -0,0 +1,10 @@ +--- +borg__targets: [] +borg__exclude_patterns: [] +borg__keep_hourly: 0 +borg__keep_daily: 0 +borg__keep_weekly: 0 +borg__keep_monthly: 0 +borg__mysql: [] +borg__postgresql: [] +... diff --git a/roles/borgmatic/filter_plugins/__pycache__/borgmatic.cpython-312.pyc b/roles/borgmatic/filter_plugins/__pycache__/borgmatic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63b034e530f728c936cde0f2ecc2bec0a700dfd6 GIT binary patch literal 883 zcmZ8fO=uHA6n?XRi8Y~AgV3N7Y$z-(*%oY1A|jZc%ti392bXPjl5E*zMKS^pJQ6^c*o1%rJK!lp@YGW!i?Wq{&D4L$$%Kf7m<4f<_X9s_W_pIR zV3^*)`3NZ3!~OPvP>s`|#bxr!@4D3qyVQy~Wmb!Nl+gpr?QwrM zpcV@Q$}O3w>qdUlYNg(seh|0)-X)>d-xs+|uHuhfLHMt#Su69X z@NI-c_*N<(ZNF+H*H^}y9$LXe5kG$YG&to^p6js1kQQ(ohh%Svfp_dw)K$<0UYG4eL zAfGb7g)oG3h3K1S1{l|VDvG{Crs|w#J7s*sR7C;baNzIO`Yyv}$qZ>KR+daUP0tYd gdzr!e>?W?sF7pz?nMw%x3M;>i9N8h~ATizb2h!iuF#rGn literal 0 HcmV?d00001 diff --git a/roles/borgmatic/filter_plugins/borgmatic.py b/roles/borgmatic/filter_plugins/borgmatic.py new file mode 100644 index 0000000..fd65d23 --- /dev/null +++ b/roles/borgmatic/filter_plugins/borgmatic.py @@ -0,0 +1,11 @@ +from urllib.parse import urlunsplit + + +class FilterModule: + def filters(self): + return { "borg__to_repo": self.to_repo } + + @staticmethod + def to_repo(target): + netloc = f"{target['user']}@{target['name']}" + return urlunsplit(("ssh", netloc, target["path"], None, None)) diff --git a/roles/borgmatic/handlers/main.yml b/roles/borgmatic/handlers/main.yml new file mode 100644 index 0000000..6f0496b --- /dev/null +++ b/roles/borgmatic/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Run daemon-reload + ansible.builtin.systemd_service: + daemon_reload: true +... diff --git a/roles/borgmatic/tasks/main.yml b/roles/borgmatic/tasks/main.yml new file mode 100644 index 0000000..7657665 --- /dev/null +++ b/roles/borgmatic/tasks/main.yml @@ -0,0 +1,136 @@ +--- +- name: Gather ansible_local facts + ansible.builtin.setup: + gather_subset: local + +- name: Install backports repository + ansible.builtin.include_role: + name: backports + when: "ansible_distribution_release in borg__backports_needed" + +- name: Install borgmatic + ansible.builtin.apt: + name: borgmatic + default_release: "{{ (release in borg__backports_needed) + | ternary(release + '-backports', omit) }}" + vars: + release: "{{ ansible_distribution_release }}" + +- name: Install borgmatic + ansible.builtin.apt: + name: borgmatic + when: "ansible_distribution_release not in borg__backports_needed" + +- name: Create configuration directory for borgmatic + ansible.builtin.file: + path: /etc/borgmatic + state: directory + owner: root + group: root + mode: u=rwx,g=rx,o= + +- name: Create SSH key + community.crypto.openssh_keypair: + path: "/etc/borgmatic/remote" + type: ed25519 + regenerate: full_idempotence + owner: root + group: root + mode: u=rw,g=,o= + register: ssh_key + +- name: Add server key to known hosts + ansible.builtin.known_hosts: + hash_host: true + host: "{{ item.0.name }}" + key: "{{ item.0.name }} {{ item.1 }}" + loop: "{{ borg__targets | subelements('hostkeys') }}" + +- name: Wait for key deployment + block: + - name: Show the generated public key + ansible.builtin.debug: + msg: "{{ ssh_key.public_key }}" + + - name: Please deploy the public key on every target + ansible.builtin.pause: null + when: "borg__targets + | map(attribute='name') + | difference(ansible_local.borgmatic_deployed_keys + | default([])) + | count > 0" + +- name: Add borgmatic configuration file + ansible.builtin.template: + src: config.yaml.j2 + dest: /etc/borgmatic/config.yaml + owner: root + group: root + mode: u=rw,g=r,o= + vars: + borg__config: + location: + source_directories: "{{ borg__backup_dirs }}" + exclude_patterns: "{{ borg__exclude_patterns }}" + repositories: "{{ borg__targets | map('borg__to_repo') }}" + borgmatic_source_directory: /tmp/borgmatic # TODO + storage: + encryption_passphrase: "{{ borg__passphrase }}" + ssh_command: "ssh -i /etc/borgmatic/remote" + retention: + keep_hourly: "{{ borg__keep_hourly }}" + keep_daily: "{{ borg__keep_daily }}" + keep_weekly: "{{ borg__keep_weekly }}" + keep_monthly: "{{ borg__keep_monthly }}" + consistency: + checks: + - repository + - archives + hooks: + postgresql_databases: "{{ borg__postgresql }}" + mysql_databases: "{{ borg__mysql }}" + +- name: Init repository + ansible.builtin.command: borgmatic init --encryption repokey + +- name: Create Ansible facts.d directory + ansible.builtin.file: + path: /etc/ansible/facts.d + state: directory + owner: root + group: root + mode: u=rwx,g=rx,o= + +- name: Check deployed keys fact + ansible.builtin.copy: + dest: /etc/ansible/facts.d/borgmatic_deployed_keys.fact + owner: root + group: root + content: "{{ borg__targets | map(attribute='name') }}" + mode: u=rw,g=r,o= + +- name: Create override directory + ansible.builtin.file: + path: /etc/systemd/system/borgmatic.timer.d + state: directory + owner: root + group: root + mode: u=rwx,g=rx,o=rx + +- name: Override borgmatic.timer + ansible.builtin.template: + src: override.conf.j2 + dest: /etc/systemd/system/borgmatic.timer.d/override.conf + owner: root + group: root + mode: u=rw,g=r,o=r + notify: + - Run daemon-reload + +- name: Start and enable borgmatic timer + ansible.builtin.systemd_service: + name: borgmatic.timer + state: started + daemon_reload: true + enabled: true +... diff --git a/roles/borgmatic/templates/config.yaml.j2 b/roles/borgmatic/templates/config.yaml.j2 new file mode 100644 index 0000000..2cceb1e --- /dev/null +++ b/roles/borgmatic/templates/config.yaml.j2 @@ -0,0 +1,5 @@ +--- +{{ ansible_managed | comment }} + +{{ borg__config | to_nice_yaml }} +... diff --git a/roles/borgmatic/templates/override.conf.j2 b/roles/borgmatic/templates/override.conf.j2 new file mode 100644 index 0000000..9142c09 --- /dev/null +++ b/roles/borgmatic/templates/override.conf.j2 @@ -0,0 +1,12 @@ +{{ ansible_managed | comment }} + +[Timer] +OnCalendar= +{% if borg__keep_hourly > 0 %} +OnCalendar=hourly +RandomizedDelaySec=20m +{% else %} +OnCalendar=daily +RandomizedDelaySec=3h +{% endif %} +FixedRandomDelay=true diff --git a/roles/borgmatic/vars/main.yml b/roles/borgmatic/vars/main.yml new file mode 100644 index 0000000..4d32f27 --- /dev/null +++ b/roles/borgmatic/vars/main.yml @@ -0,0 +1,4 @@ +--- +borg__backports_needed: + - bullseye +... diff --git a/roles/prometheus_node_exporter/defaults/main.yml b/roles/prometheus_node_exporter/defaults/main.yml new file mode 100644 index 0000000..3512219 --- /dev/null +++ b/roles/prometheus_node_exporter/defaults/main.yml @@ -0,0 +1,4 @@ +--- +prometheus__listen_port: 9100 +prometheus__smart_enabled: false +... diff --git a/roles/prometheus_node_exporter/handlers/main.yml b/roles/prometheus_node_exporter/handlers/main.yml new file mode 100644 index 0000000..475e2e0 --- /dev/null +++ b/roles/prometheus_node_exporter/handlers/main.yml @@ -0,0 +1,10 @@ +--- +- name: Run daemon-reload + ansible.builtin.systemd_service: + daemon_reload: true + +- name: Restart prometheus-node-exporter + ansible.builtin.systemd_service: + name: prometheus-node-exporter.service + state: restarted +... diff --git a/roles/prometheus_node_exporter/tasks/main.yml b/roles/prometheus_node_exporter/tasks/main.yml new file mode 100644 index 0000000..781648f --- /dev/null +++ b/roles/prometheus_node_exporter/tasks/main.yml @@ -0,0 +1,69 @@ +--- +- name: Install prometheus-node-exporter + ansible.builtin.apt: + name: + - prometheus-node-exporter + - prometheus-node-exporter-collectors + install_recommends: false # Do not install smartmontools + +- name: Configure prometheus-node-exporter + ansible.builtin.template: + src: default.j2 + dest: /etc/default/prometheus-node-exporter + owner: root + group: root + mode: u=rw,g=r,o=r + notify: + - Restart prometheus-node-exporter + +- name: Install smartmontools + ansible.builtin.apt: + name: smartmontools + when: + - "prometheus__smart_enabled" + +- name: Disable SMART monitoring + block: + - name: Get unit info for smartmon timer + command: systemctl list-unit-files --output=json prometheus-node-exporter-smartmon.timer + register: unit + + - name: Disable prometheus-node-exporter-smartmon.timer + ansible.builtin.systemd_service: + name: prometheus-node-exporter-smartmon.timer + enabled: false + state: stopped + when: "unit.stdout | from_json | count > 0" + + - name: Remove smartmon.prom + ansible.builtin.file: + path: /var/lib/prometheus/node-exporter/smartmon.prom + state: absent + when: + - "not prometheus__smart_enabled" + +- name: Create override directory + ansible.builtin.file: + path: /etc/systemd/system/prometheus-node-exporter.service.d + state: directory + owner: root + group: root + mode: u=rwx,g=rx,o=rx + +- name: Override prometheus-node-exporter.service + ansible.builtin.template: + src: override.conf.j2 + dest: /etc/systemd/system/prometheus-node-exporter.service.d/override.conf + owner: root + group: root + mode: u=rw,g=r,o=r + notify: + - Run daemon-reload + - Restart prometheus-node-exporter + +- name: Enable prometheus-node-exporter + ansible.builtin.systemd_service: + name: prometheus-node-exporter + enabled: true + state: started +... diff --git a/roles/prometheus_node_exporter/templates/default.j2 b/roles/prometheus_node_exporter/templates/default.j2 new file mode 100644 index 0000000..9539ce8 --- /dev/null +++ b/roles/prometheus_node_exporter/templates/default.j2 @@ -0,0 +1,13 @@ +{{ ansible_managed | comment }} +{# https://github.com/prometheus/exporter-toolkit/issues/91 #} +{% + set listen = + ["--web.listen-address"] + | product(prometheus__listen_addrs + | ansible.utils.ipwrap + | product([prometheus__listen_port]) + | map("join", ":")) + | map("join", "=") +%} + +ARGS="{{ listen | join(' ') }}" diff --git a/roles/prometheus_node_exporter/templates/override.conf.j2 b/roles/prometheus_node_exporter/templates/override.conf.j2 new file mode 100644 index 0000000..224d89c --- /dev/null +++ b/roles/prometheus_node_exporter/templates/override.conf.j2 @@ -0,0 +1,5 @@ +{{ ansible_managed | comment }} + +[Unit] +After=network-online.target +Wants=network-online.target