Добавить playbooks/statistica.yml

This commit is contained in:
2026-08-24 14:46:12 +03:00
parent 202828cf19
commit 6df9ba1014
+263
View File
@@ -0,0 +1,263 @@
---
- name: Collect system metrics and send to Telegram via proxy
hosts: all
gather_facts: yes
vars:
telegram_token: "8820292312:AAECFO1AEWOJTh30zNuhyjC5C81o_qJHQcM"
telegram_chat_id: "407968638"
proxy: "socks5h://administrator:60NthRegT@192.168.0.218:1080"
tasks:
- name: Gather uptime
command: uptime -p
register: uptime_output
changed_when: false
# --- Получение нагрузки (load average) ---
- name: Get load average (1, 5, 15 min)
command: uptime
register: load_output
changed_when: false
- name: Extract load averages
set_fact:
load1: "{{ (load_output.stdout.split('load average:')[1].split(',')[0] | trim) if 'load average:' in load_output.stdout else 'N/A' }}"
load5: "{{ (load_output.stdout.split('load average:')[1].split(',')[1] | trim) if 'load average:' in load_output.stdout else 'N/A' }}"
load15: "{{ (load_output.stdout.split('load average:')[1].split(',')[2] | trim) if 'load average:' in load_output.stdout else 'N/A' }}"
when: "'load average:' in load_output.stdout"
# --- НАДЁЖНОЕ получение CPU idle через vmstat (с fallback'ами) ---
- name: Get CPU idle via vmstat
shell: |
if command -v vmstat >/dev/null 2>&1; then
vmstat 1 2 | tail -1 | awk '{print $15}'
else
echo ""
fi
register: cpu_idle_vmstat
changed_when: false
failed_when: false
- name: Get CPU idle via mpstat (fallback)
shell: |
if command -v mpstat >/dev/null 2>&1; then
mpstat 1 1 | awk '/Average/ {print $12}'
else
echo ""
fi
register: cpu_idle_mpstat
changed_when: false
failed_when: false
when: cpu_idle_vmstat.stdout == ""
- name: Get CPU idle via top (fallback)
shell: |
top -bn2 | grep "Cpu(s)" | tail -1 | sed 's/.*, \([0-9.]*\)%* id.*/\1/'
register: cpu_idle_top
changed_when: false
failed_when: false
when: cpu_idle_vmstat.stdout == "" and cpu_idle_mpstat.stdout == ""
- name: Get CPU idle via /proc/stat (last resort)
shell: |
prev_idle=$(awk '/^cpu / {print $5}' /proc/stat)
prev_total=$(awk '/^cpu / {print $2+$3+$4+$5+$6+$7+$8}' /proc/stat)
sleep 1
curr_idle=$(awk '/^cpu / {print $5}' /proc/stat)
curr_total=$(awk '/^cpu / {print $2+$3+$4+$5+$6+$7+$8}' /proc/stat)
diff_idle=$((curr_idle - prev_idle))
diff_total=$((curr_total - prev_total))
if command -v bc >/dev/null 2>&1; then
echo "scale=1; ($diff_idle * 100) / $diff_total" | bc
else
awk -v diff_idle="$diff_idle" -v diff_total="$diff_total" 'BEGIN {printf "%.1f", (diff_idle * 100) / diff_total}'
fi
register: cpu_idle_proc
changed_when: false
failed_when: false
when: cpu_idle_vmstat.stdout == "" and cpu_idle_mpstat.stdout == "" and cpu_idle_top.stdout == ""
- name: Set final idle with validation
set_fact:
cpu_idle_final: >-
{%- set idle = (cpu_idle_vmstat.stdout | float) if cpu_idle_vmstat.stdout != "" else
(cpu_idle_mpstat.stdout | float) if cpu_idle_mpstat.stdout != "" else
(cpu_idle_top.stdout | float) if cpu_idle_top.stdout != "" else
(cpu_idle_proc.stdout | float) if cpu_idle_proc.stdout != "" else 90 -%}
{%- if idle > 100 or idle < 0 -%}
{{ 90 }}
{%- else -%}
{{ idle }}
{%- endif -%}
# --- Память (исправлено: используем available вместо free) ---
- name: Get memory usage in human-readable
shell: |
free -h | awk '/Mem:/ {printf "Занято: %s, Всего: %s, Доступно: %s", $3, $2, $6}'
register: memory_usage_human
changed_when: false
# --- Диск (убрана лишняя запятая) ---
- name: Get disk usage for root
shell: |
df -h / | awk 'NR==2{printf "Занято: %s, Всего: %s, Свободно: %s, Использовано: %s", $3, $2, $4, $5}' | sed 's/, $//'
register: disk_usage
changed_when: false
# --- Частота CPU ---
- name: Get CPU frequency
shell: |
if [ -f /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq ]; then
awk '{printf "%.2f GHz", $1/1000000}' /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
elif command -v lscpu >/dev/null 2>&1; then
lscpu | grep "MHz" | awk '{print $3}' | head -1 | awk '{printf "%.2f GHz", $1/1000}'
else
echo ""
fi
register: cpu_freq
changed_when: false
failed_when: false
- name: Set CPU frequency text
set_fact:
cpu_freq_text: "{{ cpu_freq.stdout if cpu_freq.stdout != '' else '' }}"
# --- Топ-5 процессов (сохраняем как список) ---
- name: Get top 5 processes by memory
shell: |
ps aux --sort=-%mem | head -6 | tail -5 | awk '{print $11 " (" $4 "%)"}'
register: top_procs
changed_when: false
- name: Join top processes into a single string
set_fact:
top_procs_joined: "{{ top_procs.stdout_lines | join('\n') }}"
# --- Температура CPU ---
- name: Get CPU temperature from thermal zone
shell: |
cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null | awk '{printf "%.1f°C", $1/1000}'
register: cpu_temp
changed_when: false
failed_when: false
- name: Fallback to sensors if thermal zone not available
shell: |
sensors | grep -i "Package id 0" | awk '{print $4}' | sed 's/+//g' | sed 's/°C//g' | awk '{printf "%.1f°C", $1}'
register: cpu_temp_sensors
changed_when: false
failed_when: false
when: cpu_temp.stdout == ""
- name: Set final CPU temperature
set_fact:
cpu_temp_final: "{{ cpu_temp.stdout if cpu_temp.stdout != '' else cpu_temp_sensors.stdout }}"
# --- Температура диска ---
- name: Check if smartctl exists
command: which smartctl
register: smartctl_check
changed_when: false
failed_when: false
- name: Get list of block devices
shell: |
lsblk -dn -o NAME | grep -E '^(sd|hd|nvme)' | head -1
register: disk_device
changed_when: false
failed_when: false
- name: Get disk temperature for first found disk
shell: |
smartctl -A /dev/{{ disk_device.stdout }} | grep -i "Temperature" | awk '{print $10}' | sed 's/°C//g' | awk '{printf "%.1f°C", $1}'
register: disk_temp
changed_when: false
failed_when: false
when: smartctl_check.rc == 0 and disk_device.stdout != ""
- name: Set disk temperature variables (safe)
set_fact:
disk_temp_text: "{{ (disk_temp | default({})).stdout | default('') }}"
disk_device_name: "{{ (disk_device | default({})).stdout | default('') }}"
# --- Расчёт процентов ---
- name: Calculate CPU usage %
set_fact:
cpu_usage: "{{ 100 - (cpu_idle_final | float) }}"
- name: Extract disk used percentage
set_fact:
disk_used_percent: "{{ disk_usage.stdout.split('Использовано:')[1].strip().replace('%', '') | float }}"
- name: Extract memory percentage
shell: |
free -m | awk 'NR==2{printf "%.0f", $3/$2*100}'
register: mem_percent
changed_when: false
# --- Прогресс-бары ---
- name: Build progress bars (20 chars)
set_fact:
bar_length: 20
cpu_bar: "{{ ((cpu_usage | float / 5) | round(0) | int) if (cpu_usage | float) < 100 else 20 }}"
mem_bar: "{{ ((mem_percent.stdout | float / 5) | round(0) | int) if (mem_percent.stdout | float) < 100 else 20 }}"
disk_bar: "{{ ((disk_used_percent | float / 5) | round(0) | int) if (disk_used_percent | float) < 100 else 20 }}"
- name: Create bar strings
set_fact:
cpu_progress: "{{ '█' * (cpu_bar | int) + '░' * (bar_length - (cpu_bar | int)) }}"
mem_progress: "{{ '█' * (mem_bar | int) + '░' * (bar_length - (mem_bar | int)) }}"
disk_progress: "{{ '█' * (disk_bar | int) + '░' * (bar_length - (disk_bar | int)) }}"
# --- Индикаторы здоровья ---
- name: Set health indicators
set_fact:
cpu_health: "{% if (cpu_usage | float) < 50 %}🟢{% elif (cpu_usage | float) < 80 %}🟡{% else %}🔴{% endif %}"
mem_health: "{% if (mem_percent.stdout | float) < 50 %}🟢{% elif (mem_percent.stdout | float) < 80 %}🟡{% else %}🔴{% endif %}"
disk_health: "{% if (disk_used_percent | float) < 70 %}🟢{% elif (disk_used_percent | float) < 85 %}🟡{% else %}🔴{% endif %}"
# --- Формирование сообщения (HTML) с пустой строкой перед прогресс-баром CPU ---
- name: Build message (HTML)
set_fact:
message_html: |
<b>📊 Системные метрики</b> <i>({{ ansible_date_time.date }} {{ ansible_date_time.time }})</i>
<b>🖥️ Хост:</b> <code>{{ ansible_hostname }}</code> ({{ ansible_default_ipv4.address }})
<b>⏱️ Время работы:</b> {{ uptime_output.stdout }}
<b>📈 Нагрузка (1,5,15 мин):</b> {{ load1 | default('N/A') }} , {{ load5 | default('N/A') }} , {{ load15 | default('N/A') }}
───────────────
<b>💻 CPU:</b> {{ (cpu_usage | float) | round(1) }}% {{ cpu_health }}{% if cpu_freq_text != '' %} ({{ cpu_freq_text }}){% endif %}
<code>{{ cpu_progress }}</code>
───────────────
<b>🧠 Память:</b> {{ mem_percent.stdout }}% {{ mem_health }} ({{ memory_usage_human.stdout }})
<code>{{ mem_progress }}</code>
───────────────
<b>💾 Диск /:</b> {{ (disk_used_percent | float) | round(1) }}% {{ disk_health }} ({{ disk_usage.stdout.split('Использовано:')[0].strip() }})
<code>{{ disk_progress }}</code>
───────────────
<b>🌡️ Температура CPU:</b> {{ cpu_temp_final | default('недоступно') }}
{% if disk_temp_text != "" %}
<b>💽 Температура диска ({{ disk_device_name }}):</b> {{ disk_temp_text }}
{% endif %}
───────────────
<b>🔥 Топ-5 процессов по памяти:</b>
<pre>{{ top_procs_joined }}</pre>
# --- Отправка в Telegram с проверкой ответа ---
- name: Send to Telegram via proxy
shell: |
response=$(curl -s -X POST \
--socks5-hostname "{{ proxy }}" \
-H "Content-Type: application/json" \
-d '{"chat_id": "{{ telegram_chat_id }}", "text": {{ message_html | to_json }}, "parse_mode": "HTML"}' \
"https://api.telegram.org/bot{{ telegram_token }}/sendMessage")
echo "Telegram API response: $response"
if echo "$response" | grep -q '"ok":true'; then
exit 0
else
echo "ERROR: Telegram API returned: $response" >&2
exit 1
fi
changed_when: false
register: tg_response
failed_when: tg_response.rc != 0