diff --git a/.gitignore b/.gitignore index c9524f066..d13491d9d 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ devops/roles/icos.postgresql/postgis_restore_log.txt devops/roles/icos.postgresql/rdflog_restore_log.txt devops/roles/icos.restheart/restheart_restore_log.txt +**/.DS_Store diff --git a/devops/get_onlyoffice_container_id.yml b/devops/get_onlyoffice_container_id.yml new file mode 100644 index 000000000..14aad66c4 --- /dev/null +++ b/devops/get_onlyoffice_container_id.yml @@ -0,0 +1,62 @@ +--- +# +# Overview: Get onlyoffice container id +# Ver: 251103 +# Updated: +# +# get_onlyoffice_container_id_and_load_fonts.yml + +- hosts: fsicos2 + become: true + gather_facts: false + + vars: + container_name: "onlyoffice" + host_fonts_dir: "/docker/nextcloud/onlyoffice-fonts/aptos_fonts" + container_fonts_dir: "/usr/share/fonts/truetype/custom" + + tasks: + - name: Detect ONLYOFFICE container ID (short) + check_mode: no + shell: > + docker ps -q --filter "name={{ container_name }}" | head -n1 + args: + executable: /bin/bash + register: container_id + changed_when: false + + - name: Fail if container not found + assert: + that: container_id.stdout | trim | length > 0 + fail_msg: "ONLYOFFICE container not found (name={{ container_name }})." + + - name: Ensure fonts directory exists inside the container + check_mode: no + shell: > + docker exec -u 0 {{ container_id.stdout | trim }} + bash -lc 'mkdir -p {{ container_fonts_dir }}' + args: + executable: /bin/bash + changed_when: false + + - name: Copy fonts into the container + check_mode: no + shell: > + docker cp {{ host_fonts_dir }}/. + {{ container_id.stdout | trim }}:{{ container_fonts_dir }}/ + args: + executable: /bin/bash + changed_when: false + + - name: Refresh font caches and ONLYOFFICE metadata + check_mode: no + shell: > + docker exec -u 0 {{ container_id.stdout | trim }} + bash -lc 'fc-cache -f -v && /usr/bin/documentserver-generate-allfonts.sh' + args: + executable: /bin/bash + changed_when: false + + - name: Print container ID + debug: + msg: "{{ container_id.stdout | trim }}" diff --git a/devops/roles/icos.nextcloud/README.md b/devops/roles/icos.nextcloud/README.md index 477e18a9d..9a4262554 100644 --- a/devops/roles/icos.nextcloud/README.md +++ b/devops/roles/icos.nextcloud/README.md @@ -43,7 +43,10 @@ - [ ] Calendar functionality - [ ] General mounting points - [ ] External storage +<<<<<<< HEAD - [ ] OnlyOffice connectivity/document editing +======= +>>>>>>> robert-devel - [ ] Check system warnings in admin panel - [ ] Review error logs @@ -125,7 +128,11 @@ apt-get install -y docker-compose-plugin docker compose exec -u www-data app php occ maintenance:mode --on || true # Make a backup +<<<<<<< HEAD /docker/nextcloud/bbclient/bin/bbclient-coldbackup +======= +docker-compose exec -u 33 db pg_dump -U nextcloud nextcloud > backup_29.0.11_$(date +%Y%m%d).sql +>>>>>>> robert-devel # Continue with docker compose stop app diff --git a/devops/roles/icos.zabbix_agent/defaults/main.yml b/devops/roles/icos.zabbix_agent/defaults/main.yml new file mode 100644 index 000000000..d7ba572fc --- /dev/null +++ b/devops/roles/icos.zabbix_agent/defaults/main.yml @@ -0,0 +1,7 @@ +--- +# Zabbix variables +zabbix_scripts_dir: /etc/zabbix/scripts +zabbix_agent_conf_file: /etc/zabbix/zabbix_agent2.conf +zabbix_agent_service: zabbix-agent2 +zabbix_server_host: icos-zbx1,127.0.0.1 + diff --git a/devops/roles/icos.zabbix_agent/files/zabbix-release_7.0-2+ubuntu22.04_all.deb b/devops/roles/icos.zabbix_agent/files/zabbix-release_7.0-2+ubuntu22.04_all.deb new file mode 100644 index 000000000..ad93d8b03 Binary files /dev/null and b/devops/roles/icos.zabbix_agent/files/zabbix-release_7.0-2+ubuntu22.04_all.deb differ diff --git a/devops/roles/icos.zabbix_agent/handlers/main.yml b/devops/roles/icos.zabbix_agent/handlers/main.yml new file mode 100644 index 000000000..a7120ec77 --- /dev/null +++ b/devops/roles/icos.zabbix_agent/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: restart zabbix-agent2 + systemd: + name: "{{ zabbix_agent_service }}" + state: restarted + daemon_reload: yes \ No newline at end of file diff --git a/devops/roles/icos.zabbix_agent/tasks/main.yml b/devops/roles/icos.zabbix_agent/tasks/main.yml new file mode 100644 index 000000000..5b8cdb08f --- /dev/null +++ b/devops/roles/icos.zabbix_agent/tasks/main.yml @@ -0,0 +1,74 @@ +--- +- name: Install Zabbix repository package on fsicos2 and fsicos3 + when: ansible_hostname in ['fsicos2', 'fsicos3'] + block: + - name: Copy Zabbix release package to /root/ + copy: + src: files/zabbix-release_7.0-2+ubuntu22.04_all.deb + dest: /root/zabbix-release_7.0-2+ubuntu22.04_all.deb + owner: root + group: root + mode: '0644' + check_mode: no + + - name: Install Zabbix repository package + apt: + deb: /root/zabbix-release_7.0-2+ubuntu22.04_all.deb + state: present + + - name: Update apt cache after adding Zabbix repository + apt: + update_cache: yes + + +- name: Install Zabbix agent2 + apt: + name: zabbix-agent2 + state: present + update_cache: yes + +- name: Configure Zabbix agent2 - Set Server parameter + lineinfile: + path: "{{ zabbix_agent_conf_file }}" + regexp: '^Server=.*$' + line: 'Server={{ zabbix_server_host }}' + register: server_changed + + + + +- name: Configure Zabbix agent2 - Set ServerActive parameter + lineinfile: + path: "{{ zabbix_agent_conf_file }}" + regexp: '^ServerActive=.*$' + line: 'ServerActive={{ zabbix_server_host }}' + register: serveractive_changed + +- name: Configure Zabbix agent2 - Set Hostname parameter + lineinfile: + path: "{{ zabbix_agent_conf_file }}" + regexp: '^Hostname=Zabbix server$' + line: "Hostname={{ ansible_hostname }}" + register: hostname_changed + +- name: Create Zabbix scripts directory + file: + path: "{{ zabbix_scripts_dir }}" + state: directory + owner: root + group: root + mode: '0755' + +- name: Trigger restart if configuration changed + debug: + msg: "Zabbix agent2 configuration has been modified" + when: server_changed.changed or serveractive_changed.changed or hostname_changed.changed + notify: restart zabbix-agent2 + changed_when: true + +- name: Ensure Zabbix agent2 service is started and enabled + systemd: + name: "{{ zabbix_agent_service }}" + state: started + enabled: yes + daemon_reload: yes \ No newline at end of file diff --git a/devops/roles/icos.zabbix_checks_fsicos2/README.md b/devops/roles/icos.zabbix_checks_fsicos2/README.md new file mode 100644 index 000000000..4cd02e1b6 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/README.md @@ -0,0 +1,62 @@ +# Ansible Role: icos.zabbix_custom_checks + +This Ansible role deploys custom Zabbix monitoring checks on fsicos2. + +## Role Structure + +``` +icos.zabbix_checks_fsicos2/ +├── defaults/ +│ └── main.yml +├── handlers/ +│ └── main.yml +├── tasks/ +│ └── main.yml +├── files/ +│ ├── check_*.sh +│ ├── check_*.py +│ ├── custom_*.conf +│ └── zabbix # Sudoers file +└── README.md +``` + +## Variables + +The following variables are defined in `defaults/main.yml`: + +- `zabbix_scripts_dir`: Directory for Zabbix scripts (default: `/etc/zabbix/scripts`) +- `zabbix_custom_dir`: Directory for custom configurations (default: `/etc/zabbix/zabbix_agent2.d`) +- `zabbix_sudoers_dir`: Directory for sudoers files (default: `/etc/sudoers.d`) +- `zabbix_agent_service`: Zabbix agent service name (default: `zabbix-agent2`) + +## Tags + +The role uses the following tags for selective deployment: + +- `fsicos2-checks`: Deploy only fsicos2 custom checks +- `zabbix-checks`: Deploy all custom checks scripts + +## Usage + +### Deploy on fsicos2 +``` +just play server-fsicos2 -t fsicos2-checks -D +``` + +## Features + +1. **Automatic directory creation**: Creates necessary Zabbix directories if they don't exist +2. **Proper file permissions**: Sets correct ownership and permissions for all files +3. **Conditional deployment**: Uses blocks with conditions to deploy files only to appropriate hosts +4. **Sudoers validation**: Validates sudoers files before deployment +5. **Service restart**: Automatically restarts Zabbix agent after file changes +6. **Tag-based deployment**: Allows selective deployment using tags + + +## Notes + +- The role checks if the host is named 'fsicos2' or 'fsicos3' or belongs to corresponding groups +- All check scripts are made executable (mode 0755) +- Configuration files are deployed with read permissions (mode 0644) +- The Zabbix agent service is restarted only when files are changed + diff --git a/devops/roles/icos.zabbix_checks_fsicos2/defaults/main.yml b/devops/roles/icos.zabbix_checks_fsicos2/defaults/main.yml new file mode 100644 index 000000000..91d9c8698 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/defaults/main.yml @@ -0,0 +1,5 @@ +# Zabbix variables +zabbix_scripts_dir: /etc/zabbix/scripts +zabbix_custom_dir: /etc/zabbix/zabbix_agent2.d +zabbix_sudoers_dir: /etc/sudoers.d +zabbix_agent_service: zabbix-agent2 \ No newline at end of file diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/check_borg_backup.sh b/devops/roles/icos.zabbix_checks_fsicos2/files/check_borg_backup.sh new file mode 100755 index 000000000..34e4c8aa6 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/check_borg_backup.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# +# Ver: 2025-09-21 by Robert +# +export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes +export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes + +REPO_BASE_DIR=$1 +REPO_DIR=$(eval echo "$REPO_BASE_DIR") +repos=$(ls "$REPO_DIR" 2>/dev/null) +current_time=$(date +%Y-%m-%d) + +# Check each repository +for repo in $repos; do + [[ "$repo" == "." || "$repo" == ".." ]] && continue + [[ "$repo" == "prometheus.repo" ]] && continue + + latest_archive=$(borg list --format '{time:%Y-%m-%d} {name}' --last=1 "$REPO_BASE_DIR/$repo" 2>/dev/null) + if [[ $? -eq 0 && "$latest_archive" != "" ]]; then + backup_date=$(echo "$latest_archive" | cut -c1-10) + if [[ "$backup_date" != "$current_time" ]]; then + echo "FAILURE1: Outdated backup in repo $repo" + exit 0 # Important: exit 0 so Zabbix gets the data + fi + else + echo "FAILURE2: Cannot check repo $repo" + exit 0 # Important: exit 0 so Zabbix gets the data + fi +done + +echo "SUCCESS: All repositories have backups for today ($current_time)" +exit 0 + diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/check_certbot_valid_days.py b/devops/roles/icos.zabbix_checks_fsicos2/files/check_certbot_valid_days.py new file mode 100755 index 000000000..ae8e04b7f --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/check_certbot_valid_days.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +""" +Certbot Certificate Monitor Script +Runs 'certbot certificates' command and extracts Certificate Name and Expiry Date +""" + +import subprocess +import re +import sys +from datetime import datetime + + +# ---------------------------------------------------------------------- +def run_certbot_certificates(): + """ + Execute 'certbot certificates' command and return the output + """ + try: + result = subprocess.run( + ['certbot', 'certificates'], + capture_output=True, + text=True, + check=True + ) + return result.stdout + except subprocess.CalledProcessError as e: + print(f"Error running certbot command: {e}", file=sys.stderr) + print(f"Return code: {e.returncode}", file=sys.stderr) + print(f"Error output: {e.stderr}", file=sys.stderr) + return None + except FileNotFoundError: + print("Error: certbot command not found. Please ensure certbot is installed.", file=sys.stderr) + return None + + +# ---------------------------------------------------------------------- +def parse_certificates(output): + """ + Parse certbot output and extract certificate names with valid days + Returns dictionary with Certificate Name as key and valid days as value + If certificate is invalid, sets value to -1 + """ + dic_certificates = {} + + # Split output into lines + lines = output.strip().split('\n') + current_cert_name = None + + for line in lines: + line = line.strip() + + # Look for Certificate Name + if line.startswith('Certificate Name:'): + current_cert_name = line.split(':', 1)[1].strip() + + # Look for Expiry Date and extract valid days + elif line.startswith('Expiry Date:') and current_cert_name: + expiry_info = line.split(':', 1)[1].strip() + + # Extract valid days using regex + # Look for patterns like "(VALID: 89 days)" or "(INVALID)" + valid_match = re.search(r'\(VALID:\s*(\d+)\s*days?\)', expiry_info, re.IGNORECASE) + invalid_match = re.search(r'\(INVALID', expiry_info, re.IGNORECASE) + + if valid_match: + # Extract the number of valid days + valid_days = int(valid_match.group(1)) + dic_certificates[current_cert_name] = valid_days + elif invalid_match: + # Certificate is invalid + dic_certificates[current_cert_name] = -1 + else: + # If we can't determine validity, assume invalid + dic_certificates[current_cert_name] = -1 + + # Reset current_cert_name for next certificate + current_cert_name = None + + return dic_certificates + +# ---------------------------------------------------------------------- +def format_output(dic_certificates): + """ + Format and print the certificate information sorted by valid days (least to most) + Input: dictionary with certificate names as keys and valid days as values + """ + if not dic_certificates: + print("No certificates found.") + sys.exit(2) + + # Sort dictionary by valid days (least to most, -1 values first) + sorted_certificates = sorted(dic_certificates.items(), key=lambda x: x[1]) + + for cert_name, valid_days in sorted_certificates: + if valid_days == -1: + print(f"Certificate: {cert_name}, EXPIRED") + sys.exit(1) + elif valid_days < 14: + print(f"Warning: Less than 14 valid days for: {cert_name}") + sys.exit(3) + + print(f"All certificates are valid with more than 30 days.") + sys.exit(0) + +# ---------------------------------------------------------------------- +def main(): + """ + Main function to orchestrate the certificate checking process + """ + + # Run certbot command + output = run_certbot_certificates() + if output is None: + sys.exit(1) + + # Parse the output + certificates = parse_certificates(output) + + # Format and display results + format_output(certificates) + + # Optional: Return certificates for programmatic use + return certificates + +if __name__ == "__main__": + main() + + + + + diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/check_docker_running.sh b/devops/roles/icos.zabbix_checks_fsicos2/files/check_docker_running.sh new file mode 100755 index 000000000..0448887ac --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/check_docker_running.sh @@ -0,0 +1,6 @@ +#!/bin/bash +############################################### +# check_docker_num.sh - Zabbix version +# Returns number of running docker containers +############################################### +docker ps -q 2>/dev/null | wc -l diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/check_lxc_running.sh b/devops/roles/icos.zabbix_checks_fsicos2/files/check_lxc_running.sh new file mode 100755 index 000000000..4695378a3 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/check_lxc_running.sh @@ -0,0 +1,13 @@ +#!/bin/bash +############################################### +# +# check_lxc_running.sh +# Returns number of running LXC containers +# +############################################### + +# Set HOME to avoid snap warning +export HOME=/root + +/snap/bin/lxc list --format=csv -c ns 2>/dev/null | grep -c "RUNNING" || echo 0 + diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/check_mounts.sh b/devops/roles/icos.zabbix_checks_fsicos2/files/check_mounts.sh new file mode 100755 index 000000000..e1aaa99c2 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/check_mounts.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +############################################### +# check_mounts.sh +# +# Paramter with correct value needed. +# Returns: +# 0 - Correct numbers of nfs mounts +# 1 - NFS mount(s) is missing. +# +############################################### + +EXPECTED=$1 +ACTUAL=$(df -P 2>/dev/null | grep ':' | wc -l) + +if [ "$ACTUAL" -eq "$EXPECTED" ]; then + echo "OK: $ACTUAL mount points found (expected: $EXPECTED)" + exit 0 +else + echo "CRITICAL: $ACTUAL mount points found (expected: $EXPECTED)" + exit 1 +fi + +exit 0 + diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/check_ping.sh b/devops/roles/icos.zabbix_checks_fsicos2/files/check_ping.sh new file mode 100755 index 000000000..9267a194e --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/check_ping.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# +# Script to check ping connectivity to specified host +# Returns 0 if ping is successful, 1 if failed +# +# Usage: ./check_ping_connectivity.sh + +# Check if destination parameter is provided +if [ -z "$1" ]; then + echo 1 + exit 1 +fi + +DESTINATION="$1" +PING_COUNT=3 +PING_TIMEOUT=2 + +# Perform ping test +ping -c $PING_COUNT -W $PING_TIMEOUT "$DESTINATION" > /dev/null 2>&1 + +# Check exit status and return result +if [ $? -eq 0 ]; then + echo 0 # Success +else + echo 1 # Failed +fi diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/custom_certbot_monitor.conf b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_certbot_monitor.conf new file mode 100644 index 000000000..219831fe6 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_certbot_monitor.conf @@ -0,0 +1 @@ +UserParameter=cert.status,sudo /etc/zabbix/scripts/check_certbot_valid_days.py diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_borg_backup.conf b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_borg_backup.conf new file mode 100644 index 000000000..2ef0e2204 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_borg_backup.conf @@ -0,0 +1,2 @@ +UserParameter=backup.borg.status[*],sudo /etc/zabbix/scripts/check_borg_backup.sh $1 + diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_docker_running.conf b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_docker_running.conf new file mode 100644 index 000000000..d5751e701 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_docker_running.conf @@ -0,0 +1 @@ +UserParameter=docker.running,/etc/zabbix/scripts/check_docker_running.sh diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_lxc_running.conf b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_lxc_running.conf new file mode 100644 index 000000000..b80ab5ca6 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_lxc_running.conf @@ -0,0 +1 @@ +UserParameter=lxc.running,sudo /etc/zabbix/scripts/check_lxc_running.sh diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_mount.conf b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_mount.conf new file mode 100644 index 000000000..b8fbdc30b --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_check_mount.conf @@ -0,0 +1 @@ +UserParameter=mount.num.status[*],/etc/zabbix/scripts/check_mounts.sh $1 diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/custom_ping_check.conf b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_ping_check.conf new file mode 100644 index 000000000..6b25d336e --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/custom_ping_check.conf @@ -0,0 +1 @@ +UserParameter=ping.check[*],/etc/zabbix/scripts/check_ping.sh $1 diff --git a/devops/roles/icos.zabbix_checks_fsicos2/files/zabbix b/devops/roles/icos.zabbix_checks_fsicos2/files/zabbix new file mode 100644 index 000000000..80953268f --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/files/zabbix @@ -0,0 +1,4 @@ +# Zabbix monitoring +Defaults:zabbix !requiretty +zabbix ALL=(ALL) NOPASSWD: /etc/zabbix/scripts/check_docker_running.sh +zabbix ALL=(ALL) NOPASSWD: /etc/zabbix/scripts/check_lxc_running.sh diff --git a/devops/roles/icos.zabbix_checks_fsicos2/handlers/main.yml b/devops/roles/icos.zabbix_checks_fsicos2/handlers/main.yml new file mode 100644 index 000000000..a7120ec77 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: restart zabbix-agent2 + systemd: + name: "{{ zabbix_agent_service }}" + state: restarted + daemon_reload: yes \ No newline at end of file diff --git a/devops/roles/icos.zabbix_checks_fsicos2/tasks/main.yml b/devops/roles/icos.zabbix_checks_fsicos2/tasks/main.yml new file mode 100644 index 000000000..3b2dbd297 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos2/tasks/main.yml @@ -0,0 +1,78 @@ +--- +- name: Ensure Zabbix directories exist + file: + path: "{{ item }}" + state: directory + owner: zabbix + group: zabbix + mode: '0755' + loop: + - "{{ zabbix_scripts_dir }}" + - "{{ zabbix_custom_dir }}" + become: yes + +- name: Deploy custom checks for fsicos2 + tags: + - fsicos2-checks + - zabbix-checks + block: + - name: Copy fsicos2 check scripts (.sh files) + copy: + src: "{{ item }}" + dest: "{{ zabbix_scripts_dir }}/" + owner: zabbix + group: zabbix + mode: '0755' + become: yes + with_fileglob: + - "files/check_*.sh" + register: sh_files + + - name: Copy fsicos2 check scripts (.py files) + copy: + src: "{{ item }}" + dest: "{{ zabbix_scripts_dir }}/" + owner: zabbix + group: zabbix + mode: '0755' + become: yes + with_fileglob: + - "files/check_*.py" + register: py_files + + - name: Copy fsicos2 custom configuration files + copy: + src: "{{ item }}" + dest: "{{ zabbix_custom_dir }}/" + owner: zabbix + group: zabbix + mode: '0644' + become: yes + with_fileglob: + - "files/custom_*.conf" + register: conf_files + + - name: Copy fsicos2 sudoers file if exists + copy: + src: "files/zabbix" + dest: "{{ zabbix_sudoers_dir }}/zabbix" + owner: root + group: root + mode: '0440' + validate: 'visudo -cf %s' + become: yes + when: lookup('ansible.builtin.fileglob', 'files/zabbix', errors='ignore') | length > 0 + register: sudo_file + + - name: Trigger zabbix restart if fsicos2 files changed + debug: + msg: "Files changed, triggering zabbix-agent2 restart" + changed_when: true + when: > + sh_files.changed or + py_files.changed or + conf_files.changed or + sudo_file.changed + notify: restart zabbix-agent2 + + diff --git a/devops/roles/icos.zabbix_checks_fsicos3/README.md b/devops/roles/icos.zabbix_checks_fsicos3/README.md new file mode 100644 index 000000000..1f763192e --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/README.md @@ -0,0 +1,73 @@ +# Ansible Role: icos.zabbix_custom_checks + +This Ansible role deploys custom Zabbix monitoring checks to specific hosts (fsicos2 and fsicos3). + +## Role Structure + +``` +icos.zabbix_custom_checks/ +├── defaults/ +│ └── main.yml # Default variables +├── handlers/ +│ └── main.yml # Service restart handlers +├── tasks/ +│ └── main.yml # Main tasks with blocks and tags +├── files/ +│ ├── fsicos2/ # Files specific to fsicos2 +│ │ ├── check_*.sh # Shell check scripts +│ │ ├── check_*.py # Python check scripts +│ │ ├── custom_*.conf # Custom configuration files +│ │ └── zabbix # Sudoers file (optional) +│ └── fsicos3/ # Files specific to fsicos3 +│ ├── check_*.sh # Shell check scripts +│ ├── check_*.py # Python check scripts +│ ├── custom_*.conf # Custom configuration files +│ └── zabbix # Sudoers file (optional) +└── README.md # This file +``` + +## Variables + +The following variables are defined in `defaults/main.yml`: + +- `zabbix_scripts_dir`: Directory for Zabbix scripts (default: `/etc/zabbix/scripts`) +- `zabbix_custom_dir`: Directory for custom configurations (default: `/etc/zabbix/zabbix_agent2.d`) +- `zabbix_sudoers_dir`: Directory for sudoers files (default: `/etc/sudoers.d`) +- `zabbix_agent_service`: Zabbix agent service name (default: `zabbix-agent2`) + +## Tags + +The role uses the following tags for selective deployment: + +- `fsicos2-custom`: Deploy only fsicos2 custom checks +- `fsicos3-custom`: Deploy only fsicos3 custom checks +- `zabbix-custom`: Deploy all custom checks + +## Usage + +### Deploy only to fsicos2 +``` +just play server-fsicos2 -t fsicos2-custom -D +``` + +### Deploy only to fsicos3 +``` +just play server-fsicos3 -t fsicos3-custom -D +``` + +## Features + +1. **Automatic directory creation**: Creates necessary Zabbix directories if they don't exist +2. **Proper file permissions**: Sets correct ownership and permissions for all files +3. **Conditional deployment**: Uses blocks with conditions to deploy files only to appropriate hosts +4. **Sudoers validation**: Validates sudoers files before deployment +5. **Service restart**: Automatically restarts Zabbix agent after file changes +6. **Tag-based deployment**: Allows selective deployment using tags + +## Notes + +- The role checks if the host is named 'fsicos2' or 'fsicos3' or belongs to corresponding groups +- All check scripts are made executable (mode 0755) +- Configuration files are deployed with read permissions (mode 0644) +- The Zabbix agent service is restarted only when files are changed + diff --git a/devops/roles/icos.zabbix_checks_fsicos3/defaults/main.yml b/devops/roles/icos.zabbix_checks_fsicos3/defaults/main.yml new file mode 100644 index 000000000..91d9c8698 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/defaults/main.yml @@ -0,0 +1,5 @@ +# Zabbix variables +zabbix_scripts_dir: /etc/zabbix/scripts +zabbix_custom_dir: /etc/zabbix/zabbix_agent2.d +zabbix_sudoers_dir: /etc/sudoers.d +zabbix_agent_service: zabbix-agent2 \ No newline at end of file diff --git a/devops/roles/icos.zabbix_checks_fsicos3/files/check_certbot_valid_days.py b/devops/roles/icos.zabbix_checks_fsicos3/files/check_certbot_valid_days.py new file mode 100755 index 000000000..ae8e04b7f --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/files/check_certbot_valid_days.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +""" +Certbot Certificate Monitor Script +Runs 'certbot certificates' command and extracts Certificate Name and Expiry Date +""" + +import subprocess +import re +import sys +from datetime import datetime + + +# ---------------------------------------------------------------------- +def run_certbot_certificates(): + """ + Execute 'certbot certificates' command and return the output + """ + try: + result = subprocess.run( + ['certbot', 'certificates'], + capture_output=True, + text=True, + check=True + ) + return result.stdout + except subprocess.CalledProcessError as e: + print(f"Error running certbot command: {e}", file=sys.stderr) + print(f"Return code: {e.returncode}", file=sys.stderr) + print(f"Error output: {e.stderr}", file=sys.stderr) + return None + except FileNotFoundError: + print("Error: certbot command not found. Please ensure certbot is installed.", file=sys.stderr) + return None + + +# ---------------------------------------------------------------------- +def parse_certificates(output): + """ + Parse certbot output and extract certificate names with valid days + Returns dictionary with Certificate Name as key and valid days as value + If certificate is invalid, sets value to -1 + """ + dic_certificates = {} + + # Split output into lines + lines = output.strip().split('\n') + current_cert_name = None + + for line in lines: + line = line.strip() + + # Look for Certificate Name + if line.startswith('Certificate Name:'): + current_cert_name = line.split(':', 1)[1].strip() + + # Look for Expiry Date and extract valid days + elif line.startswith('Expiry Date:') and current_cert_name: + expiry_info = line.split(':', 1)[1].strip() + + # Extract valid days using regex + # Look for patterns like "(VALID: 89 days)" or "(INVALID)" + valid_match = re.search(r'\(VALID:\s*(\d+)\s*days?\)', expiry_info, re.IGNORECASE) + invalid_match = re.search(r'\(INVALID', expiry_info, re.IGNORECASE) + + if valid_match: + # Extract the number of valid days + valid_days = int(valid_match.group(1)) + dic_certificates[current_cert_name] = valid_days + elif invalid_match: + # Certificate is invalid + dic_certificates[current_cert_name] = -1 + else: + # If we can't determine validity, assume invalid + dic_certificates[current_cert_name] = -1 + + # Reset current_cert_name for next certificate + current_cert_name = None + + return dic_certificates + +# ---------------------------------------------------------------------- +def format_output(dic_certificates): + """ + Format and print the certificate information sorted by valid days (least to most) + Input: dictionary with certificate names as keys and valid days as values + """ + if not dic_certificates: + print("No certificates found.") + sys.exit(2) + + # Sort dictionary by valid days (least to most, -1 values first) + sorted_certificates = sorted(dic_certificates.items(), key=lambda x: x[1]) + + for cert_name, valid_days in sorted_certificates: + if valid_days == -1: + print(f"Certificate: {cert_name}, EXPIRED") + sys.exit(1) + elif valid_days < 14: + print(f"Warning: Less than 14 valid days for: {cert_name}") + sys.exit(3) + + print(f"All certificates are valid with more than 30 days.") + sys.exit(0) + +# ---------------------------------------------------------------------- +def main(): + """ + Main function to orchestrate the certificate checking process + """ + + # Run certbot command + output = run_certbot_certificates() + if output is None: + sys.exit(1) + + # Parse the output + certificates = parse_certificates(output) + + # Format and display results + format_output(certificates) + + # Optional: Return certificates for programmatic use + return certificates + +if __name__ == "__main__": + main() + + + + + diff --git a/devops/roles/icos.zabbix_checks_fsicos3/files/check_docker_status.sh b/devops/roles/icos.zabbix_checks_fsicos3/files/check_docker_status.sh new file mode 100755 index 000000000..53b36809c --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/files/check_docker_status.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +#################################################### +# Docker status checker in LXC container +# OUTPUT: 1 = running, 0 = not running +#################################################### + +LXC_BIN="/snap/bin/lxc" +LXC_CONTAINER=$1 +DOCKER_CONTAINER=$2 + + +if [ -z "$DOCKER_CONTAINER" ]; then + echo "*** Missing parameter" + exit 1 +fi + +STATE=$(sudo $LXC_BIN exec $LXC_CONTAINER -- bash -lc "docker inspect -f '{{.State.Status}}' '$DOCKER_CONTAINER'" 2>/dev/null) + + +if [ "$STATE" = "running" ]; then + echo 1 +else + echo 0 +fi + +exit 0 diff --git a/devops/roles/icos.zabbix_checks_fsicos3/files/check_lxc_config_hash.sh b/devops/roles/icos.zabbix_checks_fsicos3/files/check_lxc_config_hash.sh new file mode 100755 index 000000000..156015826 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/files/check_lxc_config_hash.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +#################################################### +# Docker status checker in LXC container +# OUTPUT: 1 = changed, 0 = unchanged. +#################################################### + +CURRENT_HASH=$(sudo lxc config show exploredata | md5sum | awk '{print $1}') +BASELINE_HASH=$(cat /etc/zabbix/scripts/hash-keys/exploredata-hash) + + +if [ "$CURRENT_HASH" = "$BASELINE_HASH" ]; then + # Configuration unchanged + echo 0 +else + # Configuration has changed + echo 1 +fi + diff --git a/devops/roles/icos.zabbix_checks_fsicos3/files/check_mounts.sh b/devops/roles/icos.zabbix_checks_fsicos3/files/check_mounts.sh new file mode 100755 index 000000000..cf9049528 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/files/check_mounts.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +############################################### +# check_mounts.sh +# +# Paramter with correct value needed. +# Returns: +# 0 - Correct numbers of nfs mounts +# 1 - NFS mount(s) is missing. +# +############################################### + +EXPECTED=$1 +ACTUAL=$(sudo df -P 2>/dev/null | egrep ':' | wc -l) + +if [ "$ACTUAL" -eq "$EXPECTED" ]; then + echo "OK: $ACTUAL mount points found (expected: $EXPECTED)" + exit 0 +else + echo "CRITICAL: $ACTUAL mount points found (expected: $EXPECTED)" + exit 1 +fi + +exit 0 + diff --git a/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_certbot_monitor.conf b/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_certbot_monitor.conf new file mode 100644 index 000000000..219831fe6 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_certbot_monitor.conf @@ -0,0 +1 @@ +UserParameter=cert.status,sudo /etc/zabbix/scripts/check_certbot_valid_days.py diff --git a/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_check_docker_status.conf b/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_check_docker_status.conf new file mode 100644 index 000000000..70aaf6293 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_check_docker_status.conf @@ -0,0 +1 @@ +UserParameter=docker.status[*],/etc/zabbix/scripts/check_docker_status.sh $1 $2 diff --git a/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_check_lxc_config_hash.conf b/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_check_lxc_config_hash.conf new file mode 100644 index 000000000..dc2265b38 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_check_lxc_config_hash.conf @@ -0,0 +1 @@ +UserParameter=hash.status,sudo /etc/zabbix/scripts/check_lxc_config_hash.sh diff --git a/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_check_mount.conf b/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_check_mount.conf new file mode 100644 index 000000000..b8fbdc30b --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/files/userparam_check_mount.conf @@ -0,0 +1 @@ +UserParameter=mount.num.status[*],/etc/zabbix/scripts/check_mounts.sh $1 diff --git a/devops/roles/icos.zabbix_checks_fsicos3/files/zabbix b/devops/roles/icos.zabbix_checks_fsicos3/files/zabbix new file mode 100644 index 000000000..7e2a84ea4 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/files/zabbix @@ -0,0 +1,4 @@ +zabbix ALL=(ALL) NOPASSWD: /snap/bin/lxc exec * +zabbix ALL=(ALL) NOPASSWD: /snap/bin/lxc config show * +zabbix ALL=(ALL) NOPASSWD: /usr/bin/md5sum +zabbix ALL=(ALL) NOPASSWD: /etc/zabbix/scripts/check_lxc_config_hash.sh diff --git a/devops/roles/icos.zabbix_checks_fsicos3/handlers/main.yml b/devops/roles/icos.zabbix_checks_fsicos3/handlers/main.yml new file mode 100644 index 000000000..a7120ec77 --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: restart zabbix-agent2 + systemd: + name: "{{ zabbix_agent_service }}" + state: restarted + daemon_reload: yes \ No newline at end of file diff --git a/devops/roles/icos.zabbix_checks_fsicos3/tasks/main.yml b/devops/roles/icos.zabbix_checks_fsicos3/tasks/main.yml new file mode 100644 index 000000000..d0345854f --- /dev/null +++ b/devops/roles/icos.zabbix_checks_fsicos3/tasks/main.yml @@ -0,0 +1,88 @@ +--- +- name: Ensure Zabbix directories exist + file: + path: "{{ item }}" + state: directory + owner: zabbix + group: zabbix + mode: '0755' + loop: + - "{{ zabbix_scripts_dir }}" + - "{{ zabbix_custom_dir }}" + become: yes + +- name: Deploy custom checks for fsicos3 + tags: + - fsicos3-checks + - zabbix-checks + block: + - name: Copy fsicos3 check scripts (.sh files) + copy: + src: "{{ item }}" + dest: "{{ zabbix_scripts_dir }}/" + owner: zabbix + group: zabbix + mode: '0755' + become: yes + with_fileglob: + - "files/check_*.sh" + register: sh_files + + - name: Copy fsicos3 check scripts (.py files) + copy: + src: "{{ item }}" + dest: "{{ zabbix_scripts_dir }}/" + owner: zabbix + group: zabbix + mode: '0755' + become: yes + with_fileglob: + - "files/check_*.py" + register: py_files + + - name: Copy fsicos3 custom configuration files + copy: + src: "{{ item }}" + dest: "{{ zabbix_custom_dir }}/" + owner: zabbix + group: zabbix + mode: '0644' + become: yes + with_fileglob: + - "files/custom_*.conf" + register: conf_files + + - name: Copy fsicos3 userparam configuration files + copy: + src: "{{ item }}" + dest: "{{ zabbix_custom_dir }}/" + owner: zabbix + group: zabbix + mode: '0644' + become: yes + with_fileglob: + - "files/userparam_*.conf" + register: conf_files + + - name: Copy fsicos3 sudoers zabbix file + copy: + src: "files/zabbix" + dest: "{{ zabbix_sudoers_dir }}/zabbix" + owner: root + group: root + mode: '0440' + validate: 'visudo -cf %s' + become: yes + when: lookup('ansible.builtin.fileglob', 'files/zabbix', errors='ignore') | length > 0 + register: sudo_file + + - name: Trigger zabbix restart if fsicos3 files changed + ansible.builtin.debug: + msg: "*** Triggering zabbix-agent2 restart ****" + changed_when: true + when: > + sh_files.changed or + py_files.changed or + conf_files.changed or + sudo_file.changed + notify: restart zabbix-agent2 \ No newline at end of file diff --git a/devops/server-fsicos2.yml b/devops/server-fsicos2.yml index 530106d05..10b33d67a 100644 --- a/devops/server-fsicos2.yml +++ b/devops/server-fsicos2.yml @@ -17,3 +17,11 @@ - role: icos.nfs4 tags: nfs + + - role: icos.zabbix_agent + tags: zabbix-agent + + - role: icos.zabbix_custom_checks + tags: fsicos2-custom + + \ No newline at end of file diff --git a/devops/server-fsicos3.yml b/devops/server-fsicos3.yml index 48e20eb03..752b1aafe 100644 --- a/devops/server-fsicos3.yml +++ b/devops/server-fsicos3.yml @@ -17,3 +17,9 @@ - role: ops.zfs tags: zfs + + - role: icos.zabbix_agent + tags: zabbix-agent + + - role: icos.zabbix_custom_checks + tags: fsicos3-custom \ No newline at end of file diff --git a/devops/server-icos-srv1.yml b/devops/server-icos-srv1.yml new file mode 100644 index 000000000..530106d05 --- /dev/null +++ b/devops/server-icos-srv1.yml @@ -0,0 +1,19 @@ +# Upgrade certbot +# icos play fsicos2 nginx_certbot -ecertbot_state=latest + +- hosts: fsicos2 + roles: + - role: icos.server + tags: server + + - role: icos.docker + tags: docker + + - role: icos.nginx + tags: nginx + + - role: icos.bbserver + tags: bbserver + + - role: icos.nfs4 + tags: nfs diff --git a/devops/vm-fsicos3-dokku.yml b/devops/vm-fsicos3-dokku.yml index 7fb6d91ac..6679b51d2 100644 --- a/devops/vm-fsicos3-dokku.yml +++ b/devops/vm-fsicos3-dokku.yml @@ -49,3 +49,4 @@ - role: icos.dokku tags: dokku +