feat: читаем IP из address-list MikroTik вместо IP_LIST
This commit is contained in:
+2
-2
@@ -13,8 +13,8 @@ MIKROTIK_PASSWORD=your_password
|
|||||||
TELEGRAM_BOT_TOKEN=123456789:AABBccDDeeFFggHH
|
TELEGRAM_BOT_TOKEN=123456789:AABBccDDeeFFggHH
|
||||||
TELEGRAM_CHAT_ID=-1001234567890
|
TELEGRAM_CHAT_ID=-1001234567890
|
||||||
|
|
||||||
# ─── Список адресов (через запятую) ──────────────────────────────────────────
|
# Имя address-list из /ip firewall address-list на MikroTik
|
||||||
IP_LIST=192.168.1.1,192.168.1.10,192.168.1.20
|
ADDRESS_LIST_NAME=monitor
|
||||||
|
|
||||||
# ─── Параметры мониторинга ────────────────────────────────────────────────────
|
# ─── Параметры мониторинга ────────────────────────────────────────────────────
|
||||||
CHECK_INTERVAL=60
|
CHECK_INTERVAL=60
|
||||||
|
|||||||
+3
-157
@@ -8,166 +8,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
tzdata \
|
tzdata \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Зависимости
|
|
||||||
RUN pip install --no-cache-dir \
|
RUN pip install --no-cache-dir \
|
||||||
routeros-api==0.17.0 \
|
routeros-api==0.17.0 \
|
||||||
httpx==0.27.0 \
|
httpx==0.27.0
|
||||||
python-dotenv==1.0.1
|
|
||||||
|
|
||||||
# Скрипт встроен прямо в Dockerfile — не нужны дополнительные файлы
|
# Копируем скрипт из репозитория
|
||||||
RUN cat > /app/monitor.py << 'PYEOF'
|
COPY monitor.py .
|
||||||
#!/usr/bin/env python3
|
|
||||||
"""MikroTik IP Monitor — пингует адреса через MikroTik API и шлёт уведомления в Telegram."""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import logging
|
|
||||||
import asyncio
|
|
||||||
from datetime import datetime
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import routeros_api
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
# ── Настройки ──────────────────────────────────────────────────────────────
|
|
||||||
MIKROTIK_HOST = os.environ["MIKROTIK_HOST"]
|
|
||||||
MIKROTIK_PORT = int(os.getenv("MIKROTIK_PORT", "8728"))
|
|
||||||
MIKROTIK_USER = os.environ["MIKROTIK_USER"]
|
|
||||||
MIKROTIK_PASSWORD = os.environ["MIKROTIK_PASSWORD"]
|
|
||||||
|
|
||||||
TELEGRAM_BOT_TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
|
|
||||||
TELEGRAM_CHAT_ID = os.environ["TELEGRAM_CHAT_ID"]
|
|
||||||
|
|
||||||
IP_LIST = [ip.strip() for ip in os.environ["IP_LIST"].split(",") if ip.strip()]
|
|
||||||
CHECK_INTERVAL = int(os.getenv("CHECK_INTERVAL", "60"))
|
|
||||||
PING_COUNT = int(os.getenv("PING_COUNT", "3"))
|
|
||||||
PING_TIMEOUT_MS = int(os.getenv("PING_TIMEOUT_MS", "1000"))
|
|
||||||
FAILURE_THRESHOLD = int(os.getenv("FAILURE_THRESHOLD", "2"))
|
|
||||||
|
|
||||||
# ── Логирование ────────────────────────────────────────────────────────────
|
|
||||||
logging.basicConfig(
|
|
||||||
level=logging.INFO,
|
|
||||||
format="%(asctime)s [%(levelname)s] %(message)s",
|
|
||||||
datefmt="%Y-%m-%d %H:%M:%S",
|
|
||||||
)
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
# ── Telegram ───────────────────────────────────────────────────────────────
|
|
||||||
async def send_telegram(message: str) -> None:
|
|
||||||
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
|
|
||||||
payload = {"chat_id": TELEGRAM_CHAT_ID, "text": message, "parse_mode": "HTML"}
|
|
||||||
async with httpx.AsyncClient(timeout=10) as client:
|
|
||||||
try:
|
|
||||||
resp = await client.post(url, json=payload)
|
|
||||||
resp.raise_for_status()
|
|
||||||
log.info("Telegram: сообщение отправлено")
|
|
||||||
except Exception as exc:
|
|
||||||
log.error("Telegram: ошибка отправки — %s", exc)
|
|
||||||
|
|
||||||
|
|
||||||
def notify(message: str) -> None:
|
|
||||||
asyncio.run(send_telegram(message))
|
|
||||||
|
|
||||||
|
|
||||||
# ── MikroTik ping ──────────────────────────────────────────────────────────
|
|
||||||
def mikrotik_ping(connection, address: str) -> Optional[float]:
|
|
||||||
try:
|
|
||||||
api = connection.get_api()
|
|
||||||
ping_resource = api.get_resource("/ping")
|
|
||||||
results = ping_resource.call(
|
|
||||||
"",
|
|
||||||
{"address": address, "count": str(PING_COUNT), "timeout": str(PING_TIMEOUT_MS)},
|
|
||||||
)
|
|
||||||
for row in results:
|
|
||||||
if "avg-rtt" in row and row.get("avg-rtt"):
|
|
||||||
try:
|
|
||||||
return float(row["avg-rtt"].replace("ms", "").strip())
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
if row.get("packet-loss") == "100":
|
|
||||||
return None
|
|
||||||
return None
|
|
||||||
except Exception as exc:
|
|
||||||
log.warning("Ошибка пинга %s: %s", address, exc)
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# ── Основной цикл ─────────────────────────────────────────────────────────
|
|
||||||
def main() -> None:
|
|
||||||
log.info("=== MikroTik Monitor запущен ===")
|
|
||||||
log.info("Хосты: %s", IP_LIST)
|
|
||||||
log.info("Интервал: %d сек", CHECK_INTERVAL)
|
|
||||||
|
|
||||||
failure_count: dict[str, int] = {ip: 0 for ip in IP_LIST}
|
|
||||||
host_down: dict[str, bool] = {ip: False for ip in IP_LIST}
|
|
||||||
|
|
||||||
notify(
|
|
||||||
f"🟢 <b>MikroTik Monitor запущен</b>\n"
|
|
||||||
f"Хосты: <code>{', '.join(IP_LIST)}</code>\n"
|
|
||||||
f"Интервал: {CHECK_INTERVAL} сек"
|
|
||||||
)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
connection = None
|
|
||||||
try:
|
|
||||||
log.info("Подключение к MikroTik %s:%d …", MIKROTIK_HOST, MIKROTIK_PORT)
|
|
||||||
connection = routeros_api.RouterOsApiPool(
|
|
||||||
MIKROTIK_HOST,
|
|
||||||
username=MIKROTIK_USER,
|
|
||||||
password=MIKROTIK_PASSWORD,
|
|
||||||
port=MIKROTIK_PORT,
|
|
||||||
plaintext_login=True,
|
|
||||||
)
|
|
||||||
connection.get_api()
|
|
||||||
log.info("Подключено к MikroTik")
|
|
||||||
|
|
||||||
for ip in IP_LIST:
|
|
||||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
rtt = mikrotik_ping(connection, ip)
|
|
||||||
|
|
||||||
if rtt is not None:
|
|
||||||
log.info("✅ %s avg-rtt=%.1f ms", ip, rtt)
|
|
||||||
if host_down[ip]:
|
|
||||||
host_down[ip] = False
|
|
||||||
failure_count[ip] = 0
|
|
||||||
notify(
|
|
||||||
f"✅ <b>Хост восстановился</b>\n"
|
|
||||||
f"IP: <code>{ip}</code>\n"
|
|
||||||
f"RTT: {rtt:.1f} ms\n"
|
|
||||||
f"Время: {now}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
failure_count[ip] = 0
|
|
||||||
else:
|
|
||||||
failure_count[ip] += 1
|
|
||||||
log.warning("❌ %s не отвечает (%d/%d)", ip, failure_count[ip], FAILURE_THRESHOLD)
|
|
||||||
if failure_count[ip] >= FAILURE_THRESHOLD and not host_down[ip]:
|
|
||||||
host_down[ip] = True
|
|
||||||
notify(
|
|
||||||
f"🔴 <b>Хост недоступен!</b>\n"
|
|
||||||
f"IP: <code>{ip}</code>\n"
|
|
||||||
f"Не отвечает {failure_count[ip]} проверки подряд\n"
|
|
||||||
f"Время: {now}"
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as exc:
|
|
||||||
log.error("Ошибка подключения к MikroTik: %s", exc)
|
|
||||||
notify(f"⚠️ <b>Ошибка подключения к MikroTik</b>\n<code>{exc}</code>")
|
|
||||||
finally:
|
|
||||||
if connection:
|
|
||||||
try:
|
|
||||||
connection.disconnect()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
log.info("Следующая проверка через %d сек …\n", CHECK_INTERVAL)
|
|
||||||
time.sleep(CHECK_INTERVAL)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
PYEOF
|
|
||||||
|
|
||||||
ENV TZ=Europe/Moscow
|
ENV TZ=Europe/Moscow
|
||||||
CMD ["python", "-u", "/app/monitor.py"]
|
CMD ["python", "-u", "/app/monitor.py"]
|
||||||
|
|||||||
+72
-46
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
MikroTik IP Monitor — пингует адреса через MikroTik API и шлёт уведомления в Telegram.
|
MikroTik IP Monitor — читает адреса из /ip firewall address-list,
|
||||||
|
пингует их через MikroTik API и шлёт уведомления в Telegram.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -12,9 +13,6 @@ from typing import Optional
|
|||||||
|
|
||||||
import routeros_api
|
import routeros_api
|
||||||
import httpx
|
import httpx
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
# ──────────────────────────────────────────────
|
# ──────────────────────────────────────────────
|
||||||
# Настройки из переменных окружения
|
# Настройки из переменных окружения
|
||||||
@@ -27,14 +25,12 @@ MIKROTIK_PASSWORD = os.environ["MIKROTIK_PASSWORD"]
|
|||||||
TELEGRAM_BOT_TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
|
TELEGRAM_BOT_TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
|
||||||
TELEGRAM_CHAT_ID = os.environ["TELEGRAM_CHAT_ID"]
|
TELEGRAM_CHAT_ID = os.environ["TELEGRAM_CHAT_ID"]
|
||||||
|
|
||||||
# Список IP-адресов для мониторинга (через запятую в .env или задать напрямую)
|
# Имя address-list в MikroTik (/ip firewall address-list)
|
||||||
IP_LIST = [ip.strip() for ip in os.environ["IP_LIST"].split(",") if ip.strip()]
|
ADDRESS_LIST_NAME = os.environ["ADDRESS_LIST_NAME"]
|
||||||
|
|
||||||
CHECK_INTERVAL = int(os.getenv("CHECK_INTERVAL", "60")) # секунды между проверками
|
CHECK_INTERVAL = int(os.getenv("CHECK_INTERVAL", "60"))
|
||||||
PING_COUNT = int(os.getenv("PING_COUNT", "3")) # количество пингов
|
PING_COUNT = int(os.getenv("PING_COUNT", "3"))
|
||||||
PING_TIMEOUT_MS = int(os.getenv("PING_TIMEOUT_MS", "1000")) # таймаут пинга (мс)
|
PING_TIMEOUT_MS = int(os.getenv("PING_TIMEOUT_MS", "1000"))
|
||||||
|
|
||||||
# Сколько раз подряд хост должен не ответить, чтобы считаться DOWN
|
|
||||||
FAILURE_THRESHOLD = int(os.getenv("FAILURE_THRESHOLD", "2"))
|
FAILURE_THRESHOLD = int(os.getenv("FAILURE_THRESHOLD", "2"))
|
||||||
|
|
||||||
# ──────────────────────────────────────────────
|
# ──────────────────────────────────────────────
|
||||||
@@ -53,11 +49,7 @@ log = logging.getLogger(__name__)
|
|||||||
# ──────────────────────────────────────────────
|
# ──────────────────────────────────────────────
|
||||||
async def send_telegram(message: str) -> None:
|
async def send_telegram(message: str) -> None:
|
||||||
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
|
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
|
||||||
payload = {
|
payload = {"chat_id": TELEGRAM_CHAT_ID, "text": message, "parse_mode": "HTML"}
|
||||||
"chat_id": TELEGRAM_CHAT_ID,
|
|
||||||
"text": message,
|
|
||||||
"parse_mode": "HTML",
|
|
||||||
}
|
|
||||||
async with httpx.AsyncClient(timeout=10) as client:
|
async with httpx.AsyncClient(timeout=10) as client:
|
||||||
try:
|
try:
|
||||||
resp = await client.post(url, json=payload)
|
resp = await client.post(url, json=payload)
|
||||||
@@ -71,15 +63,41 @@ def notify(message: str) -> None:
|
|||||||
asyncio.run(send_telegram(message))
|
asyncio.run(send_telegram(message))
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────────────
|
||||||
|
# MikroTik: получить список IP из address-list
|
||||||
|
# ──────────────────────────────────────────────
|
||||||
|
def fetch_address_list(api) -> list[str]:
|
||||||
|
"""
|
||||||
|
Читает /ip firewall address-list и возвращает список IP
|
||||||
|
из записей с именем ADDRESS_LIST_NAME (пропускает отключённые).
|
||||||
|
"""
|
||||||
|
resource = api.get_resource("/ip/firewall/address-list")
|
||||||
|
entries = resource.get(list=ADDRESS_LIST_NAME)
|
||||||
|
|
||||||
|
ip_list = []
|
||||||
|
for entry in entries:
|
||||||
|
# Пропускаем отключённые записи
|
||||||
|
if entry.get("disabled", "false") == "true":
|
||||||
|
log.debug("Пропущена (disabled): %s", entry.get("address"))
|
||||||
|
continue
|
||||||
|
address = entry.get("address", "").strip()
|
||||||
|
# Убираем префикс /32 если есть — пингуем чистый IP
|
||||||
|
if "/" in address:
|
||||||
|
address = address.split("/")[0]
|
||||||
|
if address:
|
||||||
|
ip_list.append(address)
|
||||||
|
|
||||||
|
return ip_list
|
||||||
|
|
||||||
|
|
||||||
# ──────────────────────────────────────────────
|
# ──────────────────────────────────────────────
|
||||||
# MikroTik: пинг через API
|
# MikroTik: пинг через API
|
||||||
# ──────────────────────────────────────────────
|
# ──────────────────────────────────────────────
|
||||||
def mikrotik_ping(connection, address: str) -> Optional[float]:
|
def mikrotik_ping(api, address: str) -> Optional[float]:
|
||||||
"""
|
"""
|
||||||
Запускает ping на MikroTik. Возвращает средний avg-rtt (мс) или None если недоступен.
|
Возвращает avg-rtt (мс) или None если хост недоступен.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
api = connection.get_api()
|
|
||||||
ping_resource = api.get_resource("/ping")
|
ping_resource = api.get_resource("/ping")
|
||||||
results = ping_resource.call(
|
results = ping_resource.call(
|
||||||
"",
|
"",
|
||||||
@@ -89,18 +107,14 @@ def mikrotik_ping(connection, address: str) -> Optional[float]:
|
|||||||
"timeout": str(PING_TIMEOUT_MS),
|
"timeout": str(PING_TIMEOUT_MS),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Ищем строку с итогами (packet-loss и avg-rtt)
|
|
||||||
for row in results:
|
for row in results:
|
||||||
if "avg-rtt" in row and row.get("avg-rtt"):
|
if "avg-rtt" in row and row.get("avg-rtt"):
|
||||||
avg_rtt_str = row["avg-rtt"].replace("ms", "").strip()
|
|
||||||
try:
|
try:
|
||||||
return float(avg_rtt_str)
|
return float(row["avg-rtt"].replace("ms", "").strip())
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
if row.get("packet-loss") == "100":
|
if row.get("packet-loss") == "100":
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return None
|
return None
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
log.warning("Ошибка пинга %s: %s", address, exc)
|
log.warning("Ошибка пинга %s: %s", address, exc)
|
||||||
@@ -112,41 +126,56 @@ def mikrotik_ping(connection, address: str) -> Optional[float]:
|
|||||||
# ──────────────────────────────────────────────
|
# ──────────────────────────────────────────────
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
log.info("=== MikroTik Monitor запущен ===")
|
log.info("=== MikroTik Monitor запущен ===")
|
||||||
log.info("Хосты для проверки: %s", IP_LIST)
|
log.info("Address-list: '%s'", ADDRESS_LIST_NAME)
|
||||||
log.info("Интервал проверки: %d сек", CHECK_INTERVAL)
|
log.info("Интервал: %d сек", CHECK_INTERVAL)
|
||||||
|
|
||||||
# Состояние: счётчик последовательных ошибок и флаг «уже DOWN»
|
# Состояние хостов: счётчик ошибок и флаг DOWN
|
||||||
failure_count: dict[str, int] = {ip: 0 for ip in IP_LIST}
|
# Обновляется динамически при каждом чтении address-list
|
||||||
host_down: dict[str, bool] = {ip: False for ip in IP_LIST}
|
failure_count: dict[str, int] = {}
|
||||||
|
host_down: dict[str, bool] = {}
|
||||||
|
|
||||||
notify(
|
notify(
|
||||||
f"🟢 <b>MikroTik Monitor запущен</b>\n"
|
f"🟢 <b>MikroTik Monitor запущен</b>\n"
|
||||||
f"Хосты: <code>{', '.join(IP_LIST)}</code>\n"
|
f"Address-list: <code>{ADDRESS_LIST_NAME}</code>\n"
|
||||||
f"Интервал: {CHECK_INTERVAL} сек"
|
f"Интервал: {CHECK_INTERVAL} сек"
|
||||||
)
|
)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
connection = None
|
pool = None
|
||||||
try:
|
try:
|
||||||
log.info("Подключение к MikroTik %s:%d …", MIKROTIK_HOST, MIKROTIK_PORT)
|
log.info("Подключение к MikroTik %s:%d …", MIKROTIK_HOST, MIKROTIK_PORT)
|
||||||
connection = routeros_api.RouterOsApiPool(
|
pool = routeros_api.RouterOsApiPool(
|
||||||
MIKROTIK_HOST,
|
MIKROTIK_HOST,
|
||||||
username=MIKROTIK_USER,
|
username=MIKROTIK_USER,
|
||||||
password=MIKROTIK_PASSWORD,
|
password=MIKROTIK_PASSWORD,
|
||||||
port=MIKROTIK_PORT,
|
port=MIKROTIK_PORT,
|
||||||
plaintext_login=True,
|
plaintext_login=True,
|
||||||
)
|
)
|
||||||
connection.get_api() # проверяем соединение
|
api = pool.get_api()
|
||||||
log.info("Подключено к MikroTik")
|
log.info("Подключено к MikroTik")
|
||||||
|
|
||||||
for ip in IP_LIST:
|
# Читаем актуальный список адресов с MikroTik
|
||||||
|
ip_list = fetch_address_list(api)
|
||||||
|
|
||||||
|
if not ip_list:
|
||||||
|
log.warning("Address-list '%s' пуст или не найден!", ADDRESS_LIST_NAME)
|
||||||
|
else:
|
||||||
|
log.info("Адресов для проверки: %d → %s", len(ip_list), ip_list)
|
||||||
|
|
||||||
|
# Добавляем новые хосты в state (без сброса существующих)
|
||||||
|
for ip in ip_list:
|
||||||
|
if ip not in failure_count:
|
||||||
|
failure_count[ip] = 0
|
||||||
|
host_down[ip] = False
|
||||||
|
|
||||||
|
# Пингуем каждый адрес
|
||||||
|
for ip in ip_list:
|
||||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
rtt = mikrotik_ping(connection, ip)
|
rtt = mikrotik_ping(api, ip)
|
||||||
|
|
||||||
if rtt is not None:
|
if rtt is not None:
|
||||||
log.info("✅ %s avg-rtt=%.1f ms", ip, rtt)
|
log.info("✅ %-18s avg-rtt=%.1f ms", ip, rtt)
|
||||||
if host_down[ip]:
|
if host_down[ip]:
|
||||||
# Хост восстановился
|
|
||||||
host_down[ip] = False
|
host_down[ip] = False
|
||||||
failure_count[ip] = 0
|
failure_count[ip] = 0
|
||||||
notify(
|
notify(
|
||||||
@@ -160,29 +189,26 @@ def main() -> None:
|
|||||||
else:
|
else:
|
||||||
failure_count[ip] += 1
|
failure_count[ip] += 1
|
||||||
log.warning(
|
log.warning(
|
||||||
"❌ %s не отвечает (попытка %d/%d)",
|
"❌ %-18s не отвечает (%d/%d)",
|
||||||
ip, failure_count[ip], FAILURE_THRESHOLD,
|
ip, failure_count[ip], FAILURE_THRESHOLD,
|
||||||
)
|
)
|
||||||
|
|
||||||
if failure_count[ip] >= FAILURE_THRESHOLD and not host_down[ip]:
|
if failure_count[ip] >= FAILURE_THRESHOLD and not host_down[ip]:
|
||||||
host_down[ip] = True
|
host_down[ip] = True
|
||||||
notify(
|
notify(
|
||||||
f"🔴 <b>Хост недоступен!</b>\n"
|
f"🔴 <b>Хост недоступен!</b>\n"
|
||||||
f"IP: <code>{ip}</code>\n"
|
f"IP: <code>{ip}</code>\n"
|
||||||
|
f"Список: <code>{ADDRESS_LIST_NAME}</code>\n"
|
||||||
f"Не отвечает {failure_count[ip]} проверки подряд\n"
|
f"Не отвечает {failure_count[ip]} проверки подряд\n"
|
||||||
f"Время: {now}"
|
f"Время: {now}"
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
log.error("Ошибка подключения к MikroTik: %s", exc)
|
log.error("Ошибка: %s", exc)
|
||||||
notify(
|
notify(f"⚠️ <b>Ошибка подключения к MikroTik</b>\n<code>{exc}</code>")
|
||||||
f"⚠️ <b>Ошибка подключения к MikroTik</b>\n"
|
|
||||||
f"<code>{exc}</code>"
|
|
||||||
)
|
|
||||||
finally:
|
finally:
|
||||||
if connection:
|
if pool:
|
||||||
try:
|
try:
|
||||||
connection.disconnect()
|
pool.disconnect()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ services:
|
|||||||
- TELEGRAM_BOT_TOKEN=123456:AABBcc # ← токен от @BotFather
|
- TELEGRAM_BOT_TOKEN=123456:AABBcc # ← токен от @BotFather
|
||||||
- TELEGRAM_CHAT_ID=-1001234567890 # ← ID чата/группы
|
- TELEGRAM_CHAT_ID=-1001234567890 # ← ID чата/группы
|
||||||
|
|
||||||
# Список IP через запятую
|
# Имя address-list из /ip firewall address-list на MikroTik
|
||||||
- IP_LIST=192.168.1.1,192.168.1.10,192.168.1.20
|
- ADDRESS_LIST_NAME=monitor
|
||||||
|
|
||||||
# Параметры мониторинга
|
# Параметры мониторинга
|
||||||
- CHECK_INTERVAL=60 # интервал между проверками (сек)
|
- CHECK_INTERVAL=60 # интервал между проверками (сек)
|
||||||
|
|||||||
Reference in New Issue
Block a user