diff --git a/playbooks/borgmatic-backup.yml b/playbooks/borgmatic-backup.yml new file mode 100644 index 0000000..ada992f --- /dev/null +++ b/playbooks/borgmatic-backup.yml @@ -0,0 +1,57 @@ +--- +- name: Configure Borgmatic backup with deterministic offset + hosts: all + become: true + + vars: + borgmatic_bin: /usr/local/bin/borgmatic + backup_hour: 2 # Base hour to run backups + backup_window: 1800 # 30 min window (in seconds) + borgmatic_config_dir: /etc/borgmatic + + tasks: + - name: Ensure Borg and dependencies are present + package: + name: + - borgbackup + - python3-pip + state: present + + - name: Ensure borgmatic is installed via pip + pip: + name: borgmatic + executable: pip3 + + - name: Create borgmatic config directory + file: + path: "{{ borgmatic_config_dir }}" + state: directory + owner: root + group: root + mode: '0755' + + - name: Generate deterministic backup offset + set_fact: + backup_offset: >- + {{ ((inventory_hostname | hash('md5') | int(base=16)) % backup_window) | int }} + + - name: Split offset into minutes and seconds + set_fact: + backup_offset_minutes: "{{ backup_offset | int // 60 }}" + backup_offset_seconds: "{{ backup_offset | int % 60 }}" + + - name: Deploy borgmatic config + template: + src: templates/borg/borgmatic-config.yaml.j2 + dest: "{{ borgmatic_config_dir }}/config.yaml" + owner: root + group: root + mode: '0600' + + - name: Create cron job for borgmatic with offset + cron: + name: "Nightly borgmatic backup" + user: root + hour: "{{ backup_hour }}" + minute: "{{ backup_offset_minutes | int }}" + job: "sleep {{ backup_offset_seconds | int }} && {{ borgmatic_bin }} --verbosity 1" diff --git a/playbooks/install-node-exporter.yml b/playbooks/install-node-exporter.yml new file mode 100644 index 0000000..af0d7dd --- /dev/null +++ b/playbooks/install-node-exporter.yml @@ -0,0 +1,79 @@ +- name: Install Node Exporter from binary + hosts: all + become: true + + vars: + node_exporter_version: "1.9.1" + node_exporter_user: "node_exporter" + node_exporter_listen: "0.0.0.0:9100" + node_exporter_bin_dir: "/usr/local/bin" + node_exporter_service_path: "/etc/systemd/system/node_exporter.service" + node_exporter_arch_map: + x86_64: "amd64" + aarch64: "arm64" + armv7l: "armv7" + node_exporter_arch: "{{ node_exporter_arch_map[ansible_architecture] | default('amd64') }}" + + tasks: + - name: Debug detected architecture + debug: + msg: "Detected architecture: {{ ansible_architecture }} -> using {{ node_exporter_arch }} build" + + - name: Ensure node_exporter user exists + user: + name: "{{ node_exporter_user }}" + shell: /usr/sbin/nologin + system: true + create_home: false + + - name: Download Node Exporter archive + get_url: + url: "https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-{{ node_exporter_arch }}.tar.gz" + dest: "/tmp/node_exporter.tar.gz" + mode: "0644" + + - name: Extract Node Exporter binary + unarchive: + src: "/tmp/node_exporter.tar.gz" + dest: "/tmp/" + remote_src: true + + - name: Move Node Exporter binary into place + command: mv /tmp/node_exporter-{{ node_exporter_version }}.linux-{{ node_exporter_arch }}/node_exporter {{ node_exporter_bin_dir }}/node_exporter + + - name: Set binary permissions + file: + path: "{{ node_exporter_bin_dir }}/node_exporter" + mode: "0755" + owner: root + group: root + + - name: Create systemd service + copy: + dest: "{{ node_exporter_service_path }}" + content: | + [Unit] + Description=Prometheus Node Exporter + After=network.target + + [Service] + User={{ node_exporter_user }} + ExecStart={{ node_exporter_bin_dir }}/node_exporter --web.listen-address={{ node_exporter_listen }} + Restart=always + + [Install] + WantedBy=multi-user.target + notify: Restart node_exporter + + - name: Enable and start node_exporter + systemd: + name: node_exporter + enabled: true + state: started + daemon_reload: true + + handlers: + - name: Restart node_exporter + systemd: + name: node_exporter + state: restarted diff --git a/playbooks/install_glpi-agent.yml b/playbooks/install_glpi-agent.yml new file mode 100644 index 0000000..8cfcb06 --- /dev/null +++ b/playbooks/install_glpi-agent.yml @@ -0,0 +1,66 @@ +--- +- name: Install and configure GLPI Agent (Perl installer) + hosts: all + become: true + + vars: + glpi_agent_version: "1.15" + glpi_agent_installer_url: "https://github.com/glpi-project/glpi-agent/releases/download/{{ glpi_agent_version }}/glpi-agent-{{ glpi_agent_version }}-linux-installer.pl" + glpi_server_url: "https://glpi.ryans.tools/" # see notes below + glpi_agent_tag: "PurpleRaft" + glpi_httpd_trust: "10.0.0.0/8,192.168.0.0/16,100.64.0.0/10" # GLPI server or management subnets + + tasks: + - name: Ensure prerequisites (perl, curl, lsb-release) + package: + name: + - perl + - curl + - lsb-release + state: present + + - name: Download GLPI Agent Perl installer + get_url: + url: "{{ glpi_agent_installer_url }}" + dest: /usr/local/src/glpi-agent-installer.pl + mode: "0755" + + - name: Run the GLPI Agent installer (idempotent-ish) + command: perl /usr/local/src/glpi-agent-installer.pl + args: + creates: /usr/bin/glpi-agent + + - name: Ensure conf.d directory exists + file: + path: /etc/glpi-agent/conf.d + state: directory + mode: "0755" + + - name: Configure GLPI Agent (server/tag/trust) + copy: + dest: /etc/glpi-agent/conf.d/atlas.cfg + mode: "0644" + content: | + # Managed by Ansible + server = {{ glpi_server_url }} + tag = {{ glpi_agent_tag }} + httpd-trust = {{ glpi_httpd_trust }} + # Optional: uncomment to reduce load after first full inventory + # full-inventory-postpone = 14 + notify: restart glpi-agent + + - name: Enable and start agent service + service: + name: glpi-agent + enabled: true + state: started + + - name: Do a first inventory now (one-shot) + command: glpi-agent --server {{ glpi_server_url }} --force + changed_when: false + + handlers: + - name: restart glpi-agent + service: + name: glpi-agent + state: restarted diff --git a/playbooks/package_setup.yml b/playbooks/package_setup.yml new file mode 100644 index 0000000..d8c3c02 --- /dev/null +++ b/playbooks/package_setup.yml @@ -0,0 +1,59 @@ +--- +- name: Baseline essentials for Docker hosts + hosts: all + become: true + + vars: + # --- Feature toggles (override in Semaphore extra vars) --- + enable_install_base: true # core tools everywhere + enable_install_extras: true # QoL/debug tools + enable_remove_packages: true # remove legacy/bloat + + # --- Packages --- + base_packages: + - curl # HTTP CLI + - git # pull repos + - jq # parse JSON (docker inspect, APIs) + - ca-certificates # TLS roots for HTTPS + - iproute2 # modern net tools (ip, ss, etc.) + - acl # file ACL support (setfacl/getfacl) + + extra_packages: + - fzf # fuzzy finder (your new favorite) + - dnsutils # dig/nslookup + - htop # nicer top + - unzip # handle .zip archives + - bat # prettier cat + - tree # directory view + - bash-completion # tab completion goodness + + absent_packages: + - net-tools # ifconfig/netstat (prefer iproute2) + - snapd # don't want snaps + - apport # crash reporter + + tasks: + - name: Install base packages + apt: + name: "{{ base_packages }}" + state: present + update_cache: yes + when: enable_install_base + + - name: Install extra packages + apt: + name: "{{ extra_packages }}" + state: present + when: + - enable_install_extras + - extra_packages | length > 0 + + - name: Remove unwanted packages + apt: + name: "{{ absent_packages }}" + state: absent + purge: yes + when: + - enable_remove_packages + - absent_packages | length > 0 + diff --git a/playbooks/templates/borg/borgmatic-config.yaml.j2 b/playbooks/templates/borg/borgmatic-config.yaml.j2 new file mode 100644 index 0000000..d38e124 --- /dev/null +++ b/playbooks/templates/borg/borgmatic-config.yaml.j2 @@ -0,0 +1,29 @@ +location: + source_directories: + # ✅ Always back up system configuration + - /etc + + # Uncomment these if you want Docker data/configs + # - /srv/docker + # - /opt/docker + + # ✅ Borg repository destination (injected as a variable) + repositories: + - {{ borg_repo_url }} + + # ✅ Include hostname in archive names for multi-host dedupe + archive_name_format: "{hostname}-{now:%Y-%m-%dT%H:%M:%S}" + + # ✅ Use a dedicated SSH key for Borg backups + ssh_command: "ssh -i /root/.ssh/borg" + # To use this key each client needs the following command run: (and the public key added to the repo server) + # (First sudo su) ssh-keygen -t ed25519 -f /root/.ssh/borg + +storage: + # ✅ Encryption key; supply via vault/secret + encryption_passphrase: "{{ borg_encryption_passphrase | default('changeme') }}" + +retention: + keep_daily: 7 + keep_weekly: 4 + keep_monthly: 6