Compare commits

...

6 Commits

Author SHA1 Message Date
harry d070cbb06c Update inventories/all.yml 2026-07-04 16:37:28 +00:00
harry cb39ddac25 Update inventories/all.yml 2026-06-04 19:25:35 +00:00
harry c490f80674 Update inventories/all.yml 2026-06-04 19:24:08 +00:00
harwinder 017b415d6a Fix health check: RAM formula, exclude snap/overlay, use ASCII output
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-16 17:38:45 -04:00
harwinder ee4c3b106d Add disk and RAM health check playbook
Reports disk usage, memory, and swap per host with warnings
for partitions exceeding 85% usage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-16 17:34:36 -04:00
harwinder bec4eeb7c9 Refactor inventory into OS groups and update playbooks accordingly
Group hosts by OS (ubuntu/rocky) in inventory, refactor playbooks to
use group-targeted plays instead of ansible_os_family conditionals,
add bot host, and add Docker volume backup playbook via rsync to storage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-16 17:31:29 -04:00
6 changed files with 270 additions and 144 deletions
+19 -19
View File
@@ -1,20 +1,20 @@
all: all:
hosts: vars:
webserver: ansible_user: root
ansible_host: 192.168.2.15 children:
ansible_user: root ubuntu:
nextcloud: hosts:
ansible_host: 192.168.2.120 webserver:
ansible_user: root ansible_host: 192.168.55.10
pihole: docker:
ansible_host: 192.168.2.2 ansible_host: 192.168.55.11
ansible_user: root rocky:
docker: hosts:
ansible_host: 192.168.2.10 pihole:
ansible_user: root ansible_host: 192.168.2.2
# eve: bot:
# ansible_host: 192.168.2.12 ansible_host: 192.168.2.174
# ansible_user: root storage:
storage: ansible_host: 192.168.2.115
ansible_host: 192.168.2.115 # nextcloud:
ansible_user: root # ansible_host: 192.168.2.120
+62
View File
@@ -0,0 +1,62 @@
---
- name: Backup Docker containers and volumes to storage
hosts: docker
become: true
vars:
backup_dest: "192.168.2.115:/mnt/storage/Docker_backups"
compose_dir: "/home/harry"
volumes_dir: "/var/lib/docker/volumes"
tasks:
- name: Ensure backup destination directories exist
ansible.builtin.command:
cmd: ssh -o StrictHostKeyChecking=no root@192.168.2.115 "mkdir -p /mnt/storage/Docker_backups/compose /mnt/storage/Docker_backups/volumes"
changed_when: false
- name: Rsync compose files and configs (safe while running)
ansible.builtin.shell: |
rsync -az --delete \
--include='*/' \
--include='docker-compose.yml' \
--include='compose.yml' \
--include='.env' \
--include='*.conf' \
--include='*.yml' \
--include='*.yaml' \
--include='*.json' \
--exclude='node_modules/' \
--exclude='.git/' \
--exclude='__pycache__/' \
{{ compose_dir }}/ root@{{ backup_dest }}/compose/
register: compose_sync
- name: Get list of running containers
ansible.builtin.command: docker ps -q
register: running_containers
changed_when: false
- name: Stop all containers
ansible.builtin.command: docker stop $(docker ps -q)
when: running_containers.stdout | length > 0
- name: Rsync Docker volumes to storage
ansible.builtin.shell: |
rsync -az --delete \
{{ volumes_dir }}/ root@{{ backup_dest }}/volumes/
register: volume_sync
- name: Start all containers back up
ansible.builtin.command: docker start $(docker ps -aq)
- name: Verify containers are running
ansible.builtin.command: docker ps --format "{{ '{{' }}.Names{{ '}}' }} - {{ '{{' }}.Status{{ '}}' }}"
register: container_status
changed_when: false
- name: Backup summary
ansible.builtin.debug:
msg:
- "Compose sync: {{ 'OK' if compose_sync.rc == 0 else 'FAILED' }}"
- "Volume sync: {{ 'OK' if volume_sync.rc == 0 else 'FAILED' }}"
- "Containers running: {{ container_status.stdout_lines | length }}"
+42 -28
View File
@@ -1,11 +1,10 @@
- name: Bootstrap new Linux servers - name: Bootstrap - Install packages on Ubuntu
hosts: all hosts: ubuntu
become: yes become: true
tasks: tasks:
- name: Install packages via apt
- name: Install packages on Debian/Ubuntu ansible.builtin.apt:
apt:
name: name:
- vim - vim
- htop - htop
@@ -34,17 +33,20 @@
- mtr - mtr
- tar - tar
state: present state: present
update_cache: yes update_cache: true
when: ansible_facts['os_family'] == "Debian"
- name: Ensure EPEL repo is enabled (RHEL/CentOS/AlmaLinux) - name: Bootstrap - Install packages on Rocky Linux
yum: hosts: rocky
become: true
tasks:
- name: Ensure EPEL repo is enabled
ansible.builtin.dnf:
name: epel-release name: epel-release
state: present state: present
when: ansible_facts['os_family'] == "RedHat"
- name: Install packages on RHEL/CentOS/AlmaLinux - name: Install packages via dnf
yum: ansible.builtin.dnf:
name: name:
- tar - tar
- vim - vim
@@ -65,7 +67,7 @@
- tree - tree
- bash-completion - bash-completion
- traceroute - traceroute
- bind-utils # provides dig, nslookup - bind-utils
- ca-certificates - ca-certificates
- python3 - python3
- python3-pip - python3-pip
@@ -73,11 +75,15 @@
- sysstat - sysstat
- screen - screen
state: present state: present
update_cache: yes update_cache: true
when: ansible_facts['os_family'] == "RedHat"
- name: Bootstrap - Configure SSH access
hosts: all
become: true
tasks:
- name: Ensure root's .ssh directory exists - name: Ensure root's .ssh directory exists
file: ansible.builtin.file:
path: /root/.ssh path: /root/.ssh
state: directory state: directory
owner: root owner: root
@@ -85,7 +91,7 @@
mode: '0700' mode: '0700'
- name: Set authorized_keys for root - name: Set authorized_keys for root
copy: ansible.builtin.copy:
dest: /root/.ssh/authorized_keys dest: /root/.ssh/authorized_keys
content: | content: |
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINegitHaQG8i+s412h3wTWf/KvpeX1CEpYFva9MhHR+7 ansible-key ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINegitHaQG8i+s412h3wTWf/KvpeX1CEpYFva9MhHR+7 ansible-key
@@ -94,35 +100,43 @@
mode: '0600' mode: '0600'
- name: Permit root login via public key - name: Permit root login via public key
lineinfile: ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin\s+' regexp: '^#?PermitRootLogin\s+'
line: 'PermitRootLogin prohibit-password' line: 'PermitRootLogin prohibit-password'
state: present state: present
backup: yes backup: true
- name: Ensure PubkeyAuthentication is enabled - name: Ensure PubkeyAuthentication is enabled
lineinfile: ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config path: /etc/ssh/sshd_config
regexp: '^#?PubkeyAuthentication\s+' regexp: '^#?PubkeyAuthentication\s+'
line: 'PubkeyAuthentication yes' line: 'PubkeyAuthentication yes'
state: present state: present
- name: Ensure PasswordAuthentication is enabled - name: Ensure PasswordAuthentication is enabled
lineinfile: ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config path: /etc/ssh/sshd_config
regexp: '^#?PasswordAuthentication\s+' regexp: '^#?PasswordAuthentication\s+'
line: 'PasswordAuthentication yes' line: 'PasswordAuthentication yes'
state: present state: present
- name: Restart SSH service (Debian) - name: Bootstrap - Restart SSH on Ubuntu
service: hosts: ubuntu
become: true
tasks:
- name: Restart ssh service
ansible.builtin.service:
name: ssh name: ssh
state: restarted state: restarted
when: ansible_facts['os_family'] == "Debian"
- name: Restart SSH service (RHEL) - name: Bootstrap - Restart SSH on Rocky Linux
service: hosts: rocky
become: true
tasks:
- name: Restart sshd service
ansible.builtin.service:
name: sshd name: sshd
state: restarted state: restarted
when: ansible_facts['os_family'] == "RedHat"
+62
View File
@@ -0,0 +1,62 @@
---
- name: Check Host Availability
hosts: all
gather_facts: false
ignore_unreachable: true
tasks:
- name: Ping hosts to check availability
ansible.builtin.ping:
register: ping_result
ignore_errors: true
ignore_unreachable: true
- name: Add reachable hosts to group
ansible.builtin.group_by:
key: reachable_hosts
when: ping_result is succeeded
- name: Report offline hosts
ansible.builtin.debug:
msg: "{{ inventory_hostname }} - OFFLINE"
when: ping_result is not succeeded
delegate_to: localhost
- name: Disk and RAM Usage Report
hosts: reachable_hosts
become: true
gather_facts: true
tasks:
- name: Get disk usage (excluding snap, overlay, tmpfs)
ansible.builtin.shell: df -h --output=target,size,used,avail,pcent -x tmpfs -x devtmpfs -x squashfs -x overlay | tail -n +2
register: disk_usage
changed_when: false
- name: Calculate memory usage
ansible.builtin.set_fact:
mem_total_mb: "{{ ansible_memtotal_mb }}"
mem_used_mb: "{{ ansible_memory_mb.real.used }}"
mem_pct: "{{ ((ansible_memory_mb.real.used / ansible_memtotal_mb) * 100) | round(1) }}"
swap_total_mb: "{{ ansible_swaptotal_mb }}"
swap_used_mb: "{{ ansible_swaptotal_mb - ansible_swapfree_mb }}"
- name: Print report
ansible.builtin.debug:
msg: |
======================================================
HOST: {{ inventory_hostname }} ({{ ansible_host }})
OS: {{ ansible_distribution }} {{ ansible_distribution_version }}
======================================================
RAM: {{ mem_used_mb }}MB / {{ mem_total_mb }}MB ({{ mem_pct }}%)
SWAP: {{ swap_used_mb }}MB / {{ swap_total_mb }}MB
------------------------------------------------------
DISK:
{{ disk_usage.stdout }}
======================================================
- name: Warn on high disk usage (>85%)
ansible.builtin.debug:
msg: "WARNING: {{ item.split()[-1] }} usage on {{ item.split()[0] }} of {{ inventory_hostname }}"
loop: "{{ disk_usage.stdout_lines }}"
when: (item.split()[-1] | replace('%','') | int) > 85
+73 -78
View File
@@ -1,120 +1,115 @@
--- ---
- name: Configure timezone and NTP (LXC-Aware) - name: Configure timezone on all hosts
hosts: all hosts: all
become: yes become: true
gather_facts: true
vars: vars:
timezone_region: "America/New_York" timezone_region: "America/New_York"
ntp_server: "time.google.com"
tasks: tasks:
# ----------------------------------------------------------
# SETUP FACTS
# ----------------------------------------------------------
- name: Ensure virtualization facts are gathered
ansible.builtin.setup:
gather_subset:
- virtual
# ----------------------------------------------------------
# TIMEZONE (Required for ALL systems, LXC and VMs)
# ----------------------------------------------------------
- name: Copy timezone file - name: Copy timezone file
ansible.builtin.copy: ansible.builtin.copy:
src: "/usr/share/zoneinfo/{{ timezone_region }}" src: "/usr/share/zoneinfo/{{ timezone_region }}"
dest: /etc/localtime dest: /etc/localtime
remote_src: yes remote_src: true
register: tz_copy
- name: Write /etc/timezone - name: Write /etc/timezone
ansible.builtin.copy: ansible.builtin.copy:
dest: /etc/timezone dest: /etc/timezone
content: "{{ timezone_region }}\n" content: "{{ timezone_region }}\n"
register: tz_write
# ---------------------------------------------------------- - name: Disable NTP on Ubuntu LXC containers
# LXC CONTAINER HANDLING (Disable NTP) hosts: ubuntu
# ---------------------------------------------------------- become: true
- name: Stop and mask timesyncd on LXC (Ubuntu/Debian)
tasks:
- name: Stop and mask timesyncd on LXC
ansible.builtin.systemd: ansible.builtin.systemd:
name: systemd-timesyncd name: systemd-timesyncd
state: stopped state: stopped
enabled: no enabled: false
masked: yes masked: true
when: when: ansible_virtualization_type == "lxc"
- ansible_os_family == "Debian"
- ansible_virtualization_type == "lxc"
- name: Stop and mask chronyd on LXC (RHEL-based) - name: Disable NTP on Rocky Linux LXC containers
hosts: rocky
become: true
tasks:
- name: Stop and mask chronyd on LXC
ansible.builtin.systemd: ansible.builtin.systemd:
name: chronyd name: chronyd
state: stopped state: stopped
enabled: no enabled: false
masked: yes masked: true
when: when: ansible_virtualization_type == "lxc"
- ansible_os_family == "RedHat"
- ansible_virtualization_type == "lxc"
# ---------------------------------------------------------- - name: Configure NTP on Ubuntu VMs
# FULL VM / HARDWARE HANDLING (Configure NTP) hosts: ubuntu
# ---------------------------------------------------------- become: true
- name: Configure timesyncd on VMs (Ubuntu/Debian)
vars:
ntp_server: "time.google.com"
tasks:
- name: Configure timesyncd
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: /etc/systemd/timesyncd.conf path: /etc/systemd/timesyncd.conf
regexp: '^#?NTP=' regexp: '^#?NTP='
line: "NTP={{ ntp_server }}" line: "NTP={{ ntp_server }}"
state: present state: present
when: when: ansible_virtualization_type != "lxc"
- ansible_os_family == "Debian"
- ansible_virtualization_type != "lxc"
notify: Restart timesyncd notify: Restart timesyncd
- name: Disable default chrony pools on VMs (RHEL-based)
ansible.builtin.replace:
path: /etc/chrony.conf
regexp: '^(pool|server) .*'
replace: '# \1 removed by Ansible'
when:
- ansible_os_family == "RedHat"
- ansible_virtualization_type != "lxc"
- name: Configure chrony on VMs (RHEL-based)
ansible.builtin.lineinfile:
path: /etc/chrony.conf
line: "server {{ ntp_server }} iburst"
insertafter: EOF
state: present
when:
- ansible_os_family == "RedHat"
- ansible_virtualization_type != "lxc"
notify: Restart chronyd
# ----------------------------------------------------------
# FINAL SUMMARY
# ----------------------------------------------------------
- name: Verify current system time
ansible.builtin.command: date
register: check_time
changed_when: false
- name: Final summary
ansible.builtin.debug:
msg:
- "Setup complete on {{ inventory_hostname }} (Environment: {{ ansible_virtualization_type | default('unknown') }})"
- "System Time: {{ check_time.stdout }}"
# ----------------------------------------------------------
# HANDLERS (Only triggers for VMs)
# ----------------------------------------------------------
handlers: handlers:
- name: Restart timesyncd - name: Restart timesyncd
ansible.builtin.systemd: ansible.builtin.systemd:
name: systemd-timesyncd name: systemd-timesyncd
state: restarted state: restarted
enabled: yes enabled: true
- name: Configure NTP on Rocky Linux VMs
hosts: rocky
become: true
vars:
ntp_server: "time.google.com"
tasks:
- name: Disable default chrony pools
ansible.builtin.replace:
path: /etc/chrony.conf
regexp: '^(pool|server) .*'
replace: '# \1 removed by Ansible'
when: ansible_virtualization_type != "lxc"
- name: Configure chrony NTP server
ansible.builtin.lineinfile:
path: /etc/chrony.conf
line: "server {{ ntp_server }} iburst"
insertafter: EOF
state: present
when: ansible_virtualization_type != "lxc"
notify: Restart chronyd
handlers:
- name: Restart chronyd - name: Restart chronyd
ansible.builtin.systemd: ansible.builtin.systemd:
name: chronyd name: chronyd
state: restarted state: restarted
enabled: yes enabled: true
- name: Verify time configuration
hosts: all
become: true
tasks:
- name: Check current system time
ansible.builtin.command: date
register: check_time
changed_when: false
- name: Summary
ansible.builtin.debug:
msg: "{{ inventory_hostname }} ({{ ansible_virtualization_type | default('unknown') }}) - {{ check_time.stdout }}"
+12 -19
View File
@@ -21,33 +21,26 @@
when: ping_result is not succeeded when: ping_result is not succeeded
delegate_to: localhost delegate_to: localhost
- name: Update and Upgrade Packages - name: Update and Upgrade - Ubuntu
hosts: reachable_hosts hosts: ubuntu:&reachable_hosts
become: true become: true
gather_facts: true gather_facts: false
tasks: tasks:
- name: Update & Upgrade - Debian-based systems - name: Update & Upgrade via apt
ansible.builtin.apt: ansible.builtin.apt:
update_cache: true update_cache: true
cache_valid_time: 3600 cache_valid_time: 3600
upgrade: dist upgrade: dist
when: ansible_os_family == "Debian"
- name: Update & Upgrade - Modern RHEL-based systems (DNF) - name: Update and Upgrade - Rocky Linux
hosts: rocky:&reachable_hosts
become: true
gather_facts: false
tasks:
- name: Update & Upgrade via dnf
ansible.builtin.dnf: ansible.builtin.dnf:
name: "*" name: "*"
state: latest state: latest
update_cache: true update_cache: true
when:
- ansible_os_family == "RedHat"
- ansible_pkg_mgr == "dnf"
- name: Update & Upgrade - Legacy RHEL-based systems (YUM)
ansible.builtin.yum:
name: "*"
state: latest
update_cache: true
when:
- ansible_os_family == "RedHat"
- ansible_pkg_mgr == "yum"