109 lines
4.6 KiB
Python
109 lines
4.6 KiB
Python
|
|
"""Агент-режим: установка/удаление агента, приём метрик."""
|
||
|
|
import flet as ft
|
||
|
|
|
||
|
|
from app.core import agent as ag
|
||
|
|
from app.core import servers as servers_core
|
||
|
|
from app.ui.components import confirm_dialog, snack
|
||
|
|
|
||
|
|
|
||
|
|
class AgentPage(ft.Column):
|
||
|
|
def __init__(self, page: ft.Page, go):
|
||
|
|
super().__init__(expand=True, scroll=ft.ScrollMode.AUTO, spacing=12)
|
||
|
|
self._page = page
|
||
|
|
self.cards_col = ft.Column(spacing=10)
|
||
|
|
self.server_status = ft.Text("…", size=13)
|
||
|
|
|
||
|
|
self.controls = [
|
||
|
|
ft.Text("Агент-режим", size=28, weight=ft.FontWeight.BOLD),
|
||
|
|
ft.Text("Агент на сервере шлёт метрики каждые 5 сек по HTTP — "
|
||
|
|
"real-time графики без SSH-поллинга. Приложение слушает порт "
|
||
|
|
f"{ag.get_agent_port()}.",
|
||
|
|
size=13, color=ft.Colors.GREY_500),
|
||
|
|
ft.Row([
|
||
|
|
ft.FilledButton("Запустить приёмник", icon=ft.Icons.PLAY_ARROW,
|
||
|
|
on_click=self._start_server),
|
||
|
|
self.server_status,
|
||
|
|
]),
|
||
|
|
ft.Divider(),
|
||
|
|
self.cards_col,
|
||
|
|
]
|
||
|
|
self._reload()
|
||
|
|
self._update_server_status()
|
||
|
|
|
||
|
|
def _update_server_status(self):
|
||
|
|
self.server_status.value = (
|
||
|
|
f"✅ приёмник запущен на порту {ag.get_agent_port()}"
|
||
|
|
if ag.is_running() else "⚪ приёмник не запущен"
|
||
|
|
)
|
||
|
|
self._page.update()
|
||
|
|
|
||
|
|
def _start_server(self, e):
|
||
|
|
async def _s():
|
||
|
|
await ag.start()
|
||
|
|
self._update_server_status()
|
||
|
|
self._page.run_task(_s)
|
||
|
|
|
||
|
|
def _reload(self):
|
||
|
|
self.cards_col.controls = []
|
||
|
|
for srv in servers_core.list_servers():
|
||
|
|
self.cards_col.controls.append(self._card(srv))
|
||
|
|
self._page.update()
|
||
|
|
for srv, card in zip(servers_core.list_servers(), self.cards_col.controls):
|
||
|
|
self._page.run_task(self._fill, srv, card)
|
||
|
|
|
||
|
|
def _card(self, srv):
|
||
|
|
return ft.Card(content=ft.Container(
|
||
|
|
padding=14, width=560,
|
||
|
|
content=ft.Column([
|
||
|
|
ft.Text(srv.name, weight=ft.FontWeight.BOLD, size=16),
|
||
|
|
ft.ProgressBar(height=3),
|
||
|
|
]),
|
||
|
|
))
|
||
|
|
|
||
|
|
async def _fill(self, srv, card):
|
||
|
|
status = await ag.agent_status(srv)
|
||
|
|
metrics = ag.agent_metrics.get(srv.id)
|
||
|
|
running = status == "active"
|
||
|
|
|
||
|
|
rows = [ft.Text(f"статус: {status}", size=12,
|
||
|
|
color=ft.Colors.GREEN_300 if running else ft.Colors.GREY_500)]
|
||
|
|
if metrics:
|
||
|
|
import time
|
||
|
|
age = time.time() - metrics.get("ts", 0)
|
||
|
|
rows.append(ft.Text(
|
||
|
|
f"CPU {metrics.get('cpu')}% • RAM {metrics.get('mem_pct')}% • "
|
||
|
|
f"Диск {metrics.get('disk')}% • load {metrics.get('load')} • "
|
||
|
|
f"обновлено {age:.0f} сек назад",
|
||
|
|
size=11, color=ft.Colors.BLUE_300))
|
||
|
|
btns = []
|
||
|
|
if not running:
|
||
|
|
btns.append(ft.FilledButton("Установить агента", icon=ft.Icons.DOWNLOAD,
|
||
|
|
on_click=lambda e, s=srv: self._install(s)))
|
||
|
|
else:
|
||
|
|
btns.append(ft.OutlinedButton("Удалить агента",
|
||
|
|
on_click=lambda e, s=srv: self._uninstall(s)))
|
||
|
|
rows.append(ft.Row(btns))
|
||
|
|
card.content.content.controls[1] = ft.Column(rows, spacing=4)
|
||
|
|
self._page.update()
|
||
|
|
|
||
|
|
def _install(self, srv):
|
||
|
|
from app.core.tasks import tasks
|
||
|
|
import socket
|
||
|
|
app_host = socket.gethostbyname(socket.gethostname())
|
||
|
|
async def job(log):
|
||
|
|
log(f"адрес приложения для агента: {app_host}:{ag.get_agent_port()}")
|
||
|
|
ok = await ag.install_agent(srv, app_host, log)
|
||
|
|
log("готово" if ok else "ошибка установки")
|
||
|
|
tasks.start("agent", "установка агента", srv.id, job,
|
||
|
|
on_done=lambda r: self._reload())
|
||
|
|
snack(self._page, f"Установка агента на {srv.name}…")
|
||
|
|
|
||
|
|
def _uninstall(self, srv):
|
||
|
|
def do():
|
||
|
|
async def _d():
|
||
|
|
await ag.uninstall_agent(srv)
|
||
|
|
self._reload()
|
||
|
|
self._page.run_task(_d)
|
||
|
|
confirm_dialog(self._page, "Удалить агента?",
|
||
|
|
f"dm-agent будет остановлен и удалён с «{srv.name}».", do)
|