Files
Raspberry_awx/playbooks/statistica_rasp.yml
T

278 lines
12 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
- name: Collect system metrics and send to Telegram (with optional 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) ---
- 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 с проверкой HTTP-кода и поддержкой опционального прокси ---
- name: Send to Telegram via proxy
shell: |
set -e
if [ -n "{{ proxy }}" ]; then
proxy_opt="--socks5-hostname {{ proxy }}"
else
proxy_opt=""
fi
response=$(curl -s -w "\n%{http_code}" -X POST $proxy_opt \
-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" 2>&1)
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')
echo "HTTP code: $http_code"
echo "Response body: $body"
if [ "$http_code" -eq 200 ]; then
if echo "$body" | grep -q '"ok":true'; then
echo "Message sent successfully"
exit 0
else
echo "ERROR: Telegram API returned ok=false: $body" >&2
exit 1
fi
else
echo "ERROR: HTTP error $http_code: $body" >&2
exit 1
fi
changed_when: false
register: tg_response
failed_when: tg_response.rc != 0