diff --git a/.gitignore b/.gitignore index ca169d7..2c2b4e1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ __pycache__/ .DS_Store .vscode/ .idea/ +*.deb diff --git a/README.md b/README.md index e38c059..9d4d175 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ info-user/ │ ├── agent.py │ ├── config.json │ └── install.sh +├── agent-deb/ # Исходники .deb пакета (dpkg-deb --build) ├── data/ # SQLite БД (создаётся при запуске) ├── docker-compose.yml ├── nginx.conf @@ -70,6 +71,23 @@ http://localhost 5. **Установить агент** на клиентский ПК (Linux): +### Debian/Ubuntu/Astra Linux (рекомендуется) + +```bash +# Установить .deb пакет +sudo dpkg -i info-user-agent_1.0.0_all.deb + +# Настроить сервер и токен (интерактивно) +sudo info-user-agent-setup + +# Или вручную: +sudo nano /opt/info-user-agent/config.json +``` + +Либо через репозиторий (добавив его в `/etc/apt/sources.list.d/`). + +### Вручную (любой Linux) + ```bash cd agent sudo bash install.sh diff --git a/agent-deb/DEBIAN/control b/agent-deb/DEBIAN/control new file mode 100644 index 0000000..67cb000 --- /dev/null +++ b/agent-deb/DEBIAN/control @@ -0,0 +1,14 @@ +Package: info-user-agent +Version: 1.0.0 +Section: admin +Priority: optional +Architecture: all +Depends: python3, python3-psutil, python3-requests +Maintainer: Hidosi +Description: InfoUser Monitor - агент мониторинга ПК + Агент собирает метрики компьютера (CPU, RAM, диски, процессы, пользователь, IP) + и отправляет их раз в час на сервер InfoUser Monitor. + . + После установки запустите: + sudo info-user-agent-setup + для настройки адреса сервера и токена. diff --git a/agent-deb/DEBIAN/postinst b/agent-deb/DEBIAN/postinst new file mode 100755 index 0000000..f235252 --- /dev/null +++ b/agent-deb/DEBIAN/postinst @@ -0,0 +1,20 @@ +#!/bin/sh +set -e + +systemctl daemon-reload 2>/dev/null || true +systemctl enable info-user-agent.timer 2>/dev/null || true +systemctl start info-user-agent.timer 2>/dev/null || true + +cat </dev/null || true + +exit 0 diff --git a/agent-deb/DEBIAN/prerm b/agent-deb/DEBIAN/prerm new file mode 100755 index 0000000..7b7b359 --- /dev/null +++ b/agent-deb/DEBIAN/prerm @@ -0,0 +1,7 @@ +#!/bin/sh +set -e + +systemctl stop info-user-agent.timer 2>/dev/null || true +systemctl disable info-user-agent.timer 2>/dev/null || true + +exit 0 diff --git a/agent-deb/lib/systemd/system/info-user-agent.service b/agent-deb/lib/systemd/system/info-user-agent.service new file mode 100644 index 0000000..a7310df --- /dev/null +++ b/agent-deb/lib/systemd/system/info-user-agent.service @@ -0,0 +1,8 @@ +[Unit] +Description=InfoUser Agent +After=network.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/python3 /opt/info-user-agent/agent.py +User=root diff --git a/agent-deb/lib/systemd/system/info-user-agent.timer b/agent-deb/lib/systemd/system/info-user-agent.timer new file mode 100644 index 0000000..978ddac --- /dev/null +++ b/agent-deb/lib/systemd/system/info-user-agent.timer @@ -0,0 +1,9 @@ +[Unit] +Description=InfoUser Agent Timer + +[Timer] +OnCalendar=hourly +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/agent-deb/opt/info-user-agent/agent.py b/agent-deb/opt/info-user-agent/agent.py new file mode 100755 index 0000000..84af438 --- /dev/null +++ b/agent-deb/opt/info-user-agent/agent.py @@ -0,0 +1,146 @@ +import psutil +import socket +import platform +import time +import os +import getpass +import json +import requests +import logging +from pathlib import Path + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(message)s", +) + + +def load_config(): + cfg_path = Path(__file__).with_suffix("").parent / "config.json" + if cfg_path.exists(): + with open(cfg_path, "r", encoding="utf-8") as f: + return json.load(f) + return { + "server_url": "http://127.0.0.1", + "agent_token": "agent-secret-token", + "interval_minutes": 60, + "send_public_ip": False, + } + + +def get_local_ip(): + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.settimeout(1) + s.connect(("8.8.8.8", 80)) + ip = s.getsockname()[0] + s.close() + return ip + except Exception: + return "127.0.0.1" + + +def get_public_ip(): + try: + r = requests.get("https://api.ipify.org", timeout=5) + return r.text.strip() + except Exception: + return None + + +def get_uptime(): + return int(time.time() - psutil.boot_time()) + + +def get_disk_info(): + disks = [] + for part in psutil.disk_partitions(all=False): + try: + usage = psutil.disk_usage(part.mountpoint) + disks.append({ + "device": part.device, + "mountpoint": part.mountpoint, + "total_gb": round(usage.total / (2**30), 1), + "used_gb": round(usage.used / (2**30), 1), + "free_gb": round(usage.free / (2**30), 1), + "percent": usage.percent, + }) + except Exception: + continue + return disks + + +def get_cpu_temp(): + try: + temps = psutil.sensors_temperatures() + if temps: + for name, entries in temps.items(): + for entry in entries: + if entry.current: + return round(entry.current, 1) + except Exception: + pass + return None + + +def get_load_avg(): + try: + return ", ".join(str(x) for x in os.getloadavg()) + except Exception: + return None + + +def get_top_processes(limit=10): + procs = [] + for p in psutil.process_iter(["pid", "name", "cpu_percent", "memory_percent"]): + try: + procs.append({ + "pid": p.info["pid"], + "name": p.info["name"], + "cpu_percent": round(p.info["cpu_percent"] or 0, 1), + "ram_percent": round((p.info["memory_percent"] or 0), 1), + }) + except Exception: + continue + procs.sort(key=lambda x: x["cpu_percent"], reverse=True) + return procs[:limit] + + +def collect(): + cfg = load_config() + payload = { + "hostname": socket.gethostname(), + "username": getpass.getuser(), + "os_info": f"{platform.system()} {platform.release()}", + "local_ip": get_local_ip(), + "public_ip": get_public_ip() if cfg.get("send_public_ip") else None, + "uptime_sec": get_uptime(), + "cpu_percent": psutil.cpu_percent(interval=1), + "ram_percent": psutil.virtual_memory().percent, + "ram_total_gb": round(psutil.virtual_memory().total / (2**30), 1), + "disk_info": get_disk_info(), + "cpu_temp": get_cpu_temp(), + "load_avg": get_load_avg(), + "processes": get_top_processes(10), + } + return payload, cfg + + +def send(payload, cfg): + url = cfg["server_url"].rstrip("/") + "/api/heartbeat" + headers = {"Authorization": f"Bearer {cfg['agent_token']}", "Content-Type": "application/json"} + try: + resp = requests.post(url, json=payload, headers=headers, timeout=15) + resp.raise_for_status() + logging.info("Heartbeat sent: %s", resp.status_code) + except Exception as e: + logging.error("Failed to send heartbeat: %s", e) + + +def main(): + payload, cfg = collect() + send(payload, cfg) + + +if __name__ == "__main__": + main() diff --git a/agent-deb/usr/bin/info-user-agent-setup b/agent-deb/usr/bin/info-user-agent-setup new file mode 100755 index 0000000..45a35a0 --- /dev/null +++ b/agent-deb/usr/bin/info-user-agent-setup @@ -0,0 +1,32 @@ +#!/bin/bash +# InfoUser Agent - интерактивная настройка + +set -e + +CONFIG_FILE="/opt/info-user-agent/config.json" + +echo "" +echo "=== Настройка InfoUser Agent ===" +echo "" + +read -p "URL сервера (например http://192.168.255.180:3000): " SERVER_URL +read -p "Токен агента: " AGENT_TOKEN + +cat > "$CONFIG_FILE" <