v1.8.60: multi-type status check + --add in skill + skill docs update

- _check_status_one: proper connectivity check per server type
  (SSH/SQL/Redis/Grafana/Prometheus/WinRM/RDP)
- ping_server uses _check_status_one instead of paramiko-only
- check_status shows server type column
- skill-ssh.md: allow --add, document it, update --status description
- CLAUDE.md: add --add/--remove/--set-note to command reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-02-25 05:26:24 -05:00
parent 1c4288ba93
commit 3a5d1b27fc
8 changed files with 108 additions and 12 deletions

View File

@@ -136,6 +136,9 @@ tools/
/ssh --list # Все серверы /ssh --list # Все серверы
/ssh --info ALIAS # Инфо (без creds) /ssh --info ALIAS # Инфо (без creds)
/ssh --status # Online/offline /ssh --status # Online/offline
/ssh --add ALIAS IP PORT USER PASS # Добавить сервер
/ssh --remove ALIAS # Удалить сервер
/ssh --set-note ALIAS "desc" # Обновить заметки
``` ```
## Конфигурация ## Конфигурация

View File

@@ -13,7 +13,7 @@
- Скрипт сам читает credentials, подключается, выполняет, возвращает результат - Скрипт сам читает credentials, подключается, выполняет, возвращает результат
- **МАКСИМУМ 1 попытка** подключения. Если timeout/ошибка — сообщи, НЕ повторяй - **МАКСИМУМ 1 попытка** подключения. Если timeout/ошибка — сообщи, НЕ повторяй
- fail2ban банит IP после 5-10 неудач — спам попытками УБЬЁТ доступ к серверу - fail2ban банит IP после 5-10 неудач — спам попытками УБЬЁТ доступ к серверу
- **Серверы добавляются ТОЛЬКО через GUI** ServerManager, НЕ через CLI - **Серверы можно добавлять** через `--add` (см. ниже) или через GUI ServerManager
## Аргументы ## Аргументы
@@ -31,10 +31,11 @@ python ~/.server-connections/ssh.py --list
python ~/.server-connections/ssh.py --info ALIAS python ~/.server-connections/ssh.py --info ALIAS
``` ```
### Статус всех серверов (alias + online/offline) ### Статус всех серверов (alias + тип + online/offline)
```bash ```bash
python ~/.server-connections/ssh.py --status python ~/.server-connections/ssh.py --status
``` ```
Проверяет каждый сервер по его типу: SSH-подключение, SQL-коннект, Redis PING, HTTP health-check и т.д.
### Обновить заметки сервера ### Обновить заметки сервера
```bash ```bash
@@ -47,6 +48,15 @@ python ~/.server-connections/ssh.py --remove ALIAS
``` ```
**Спроси подтверждение у пользователя перед удалением!** **Спроси подтверждение у пользователя перед удалением!**
### Добавить сервер
```bash
python ~/.server-connections/ssh.py --add ALIAS IP PORT USER PASSWORD [--note "описание"]
```
- Автоматически устанавливает SSH-ключ после добавления
- Обновляет `~/.ssh/config`
- **Спроси у пользователя все параметры перед добавлением!**
- Тип сервера по умолчанию — ssh. Для других типов (mariadb, redis и т.д.) — добавь через GUI
## SSH-команды (тип: ssh) ## SSH-команды (тип: ssh)
### Выполнить команду на сервере ### Выполнить команду на сервере

View File

@@ -314,9 +314,8 @@ def install_key(server: dict):
def ping_server(server: dict): def ping_server(server: dict):
try: try:
client = get_client(server) status = _check_status_one(server)
client.close() print(f"{server['alias']}: {status}")
print(f"{server['alias']}: ONLINE")
except Exception as e: except Exception as e:
print(f"{server['alias']}: OFFLINE ({type(e).__name__})") print(f"{server['alias']}: OFFLINE ({type(e).__name__})")
@@ -388,18 +387,102 @@ def server_info(alias: str):
print(f"Notes: {notes}") print(f"Notes: {notes}")
def _check_status_one(server: dict) -> str:
"""Check connectivity for a single server based on its type."""
stype = server.get("type", "ssh")
if stype in ("ssh", "telnet"):
client = get_client(server)
client.close()
return "ONLINE"
if stype in ("mariadb", "mysql", "mssql", "postgresql"):
host = server["ip"]
port = server.get("port", 3306)
user = server.get("user", "root")
password = server.get("password", "")
database = server.get("database", "")
if stype in ("mariadb", "mysql"):
import pymysql
conn = pymysql.connect(host=host, port=port, user=user, password=password,
database=database or None, connect_timeout=10)
elif stype == "mssql":
import pymssql
conn = pymssql.connect(server=host, port=port, user=user, password=password,
database=database or None, login_timeout=10)
elif stype == "postgresql":
import psycopg2
port = server.get("port", 5432)
conn = psycopg2.connect(host=host, port=port, user=user, password=password,
dbname=database or None, connect_timeout=10)
conn.close()
return "ONLINE"
if stype == "redis":
import redis as redis_lib
r = redis_lib.Redis(host=server["ip"], port=server.get("port", 6379),
password=server.get("password", "") or None,
db=server.get("db_index", 0), socket_timeout=10,
ssl=server.get("ssl", False))
r.ping()
r.close()
return "ONLINE"
if stype == "grafana":
import requests
host = server["ip"]
port = server.get("port", 3000)
protocol = "https" if server.get("ssl", False) else "http"
base_url = server.get("base_url", f"{protocol}://{host}:{port}")
resp = requests.get(f"{base_url.rstrip('/')}/api/health", timeout=10,
verify=server.get("ssl_verify", True))
resp.raise_for_status()
return "ONLINE"
if stype == "prometheus":
import requests
host = server["ip"]
port = server.get("port", 9090)
protocol = "https" if server.get("ssl", False) else "http"
base_url = server.get("base_url", f"{protocol}://{host}:{port}")
auth = None
user = server.get("user", "")
password = server.get("password", "")
if user and password:
auth = (user, password)
resp = requests.get(f"{base_url.rstrip('/')}/api/v1/status/buildinfo",
auth=auth, timeout=10, verify=server.get("ssl_verify", True))
resp.raise_for_status()
return "ONLINE"
if stype == "winrm":
session = _get_winrm_session(server)
result = session.run_cmd("echo ok")
if result.status_code == 0:
return "ONLINE"
return "OFFLINE"
# rdp/vnc — just TCP ping
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(10)
port = server.get("port", 3389 if stype == "rdp" else 5900)
sock.connect((server["ip"], port))
sock.close()
return "ONLINE"
def check_status(): def check_status():
_, servers = load_servers() _, servers = load_servers()
print(f"{'Alias':<20} {'Status':<10}") print(f"{'Alias':<20} {'Type':<12} {'Status':<10}")
print("-" * 30) print("-" * 42)
for alias, s in servers.items(): for alias, s in servers.items():
stype = s.get("type", "ssh")
try: try:
client = get_client(s) status = _check_status_one(s)
client.close()
status = "ONLINE"
except Exception: except Exception:
status = "OFFLINE" status = "OFFLINE"
print(f"{alias:<20} {status:<10}") print(f"{alias:<20} {stype:<12} {status:<10}")
def add_server(args): def add_server(args):

View File

@@ -1,6 +1,6 @@
"""Version info for ServerManager.""" """Version info for ServerManager."""
__version__ = "1.8.59" __version__ = "1.8.60"
__app_name__ = "ServerManager" __app_name__ = "ServerManager"
__author__ = "aibot777" __author__ = "aibot777"
__description__ = "Desktop GUI for managing remote servers" __description__ = "Desktop GUI for managing remote servers"