- Создан LogBoard клиент для отправки логов с удаленных серверов - Добавлен API эндпоинт /api/logs/remote с аутентификацией - Реализована структурированная система сохранения логов - Исправлена совместимость Docker client библиотеки - Добавлена полная документация и тестирование
267 lines
10 KiB
Python
267 lines
10 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Тестовый скрипт для проверки системы удаленных клиентов LogBoard
|
||
Автор: Сергей Антропов
|
||
Сайт: https://devops.org.ru
|
||
"""
|
||
|
||
import asyncio
|
||
import aiohttp
|
||
import json
|
||
import os
|
||
import subprocess
|
||
import time
|
||
from datetime import datetime
|
||
|
||
# Конфигурация теста
|
||
SERVER_URL = os.getenv('LOGBOARD_SERVER_URL', 'http://localhost:9001')
|
||
API_KEY = os.getenv('LOGBOARD_API_KEY', 'dev-key-123')
|
||
HOSTNAME = os.getenv('HOSTNAME', 'test-host')
|
||
|
||
async def test_server_availability():
|
||
"""Тестирование доступности сервера"""
|
||
print("🔍 Проверка доступности сервера LogBoard...")
|
||
|
||
try:
|
||
async with aiohttp.ClientSession() as session:
|
||
async with session.get(
|
||
f"{SERVER_URL}/",
|
||
timeout=aiohttp.ClientTimeout(total=10)
|
||
) as response:
|
||
if response.status == 200:
|
||
print("✅ Сервер LogBoard доступен")
|
||
return True
|
||
else:
|
||
print(f"❌ Сервер недоступен, статус: {response.status}")
|
||
return False
|
||
except Exception as e:
|
||
print(f"❌ Ошибка подключения к серверу: {e}")
|
||
return False
|
||
|
||
async def test_remote_logs_endpoint():
|
||
"""Тестирование эндпоинта для удаленных логов"""
|
||
print("📤 Тестирование отправки логов...")
|
||
|
||
test_data = {
|
||
"hostname": HOSTNAME,
|
||
"container_name": "test-nginx",
|
||
"logs": [
|
||
f"{datetime.now().isoformat()} nginx: [info] Test log line 1",
|
||
f"{datetime.now().isoformat()} nginx: [info] Test log line 2",
|
||
f"{datetime.now().isoformat()} nginx: [error] Test error log",
|
||
f"{datetime.now().isoformat()} nginx: [warn] Test warning log"
|
||
],
|
||
"timestamp": datetime.now().isoformat()
|
||
}
|
||
|
||
headers = {
|
||
'Authorization': f'Bearer {API_KEY}',
|
||
'Content-Type': 'application/json',
|
||
'User-Agent': 'LogBoard-System-Test/1.0'
|
||
}
|
||
|
||
try:
|
||
async with aiohttp.ClientSession() as session:
|
||
async with session.post(
|
||
f"{SERVER_URL}/api/logs/remote",
|
||
json=test_data,
|
||
headers=headers,
|
||
timeout=aiohttp.ClientTimeout(total=30)
|
||
) as response:
|
||
print(f"📊 Статус ответа: {response.status}")
|
||
|
||
if response.status == 200:
|
||
result = await response.json()
|
||
print("✅ Логи успешно отправлены:")
|
||
print(f" - Хост: {result.get('hostname')}")
|
||
print(f" - Контейнер: {result.get('container_name')}")
|
||
print(f" - Сообщение: {result.get('message')}")
|
||
print(f" - Файл: {result.get('log_file')}")
|
||
return True
|
||
else:
|
||
error_text = await response.text()
|
||
print(f"❌ Ошибка отправки логов: {response.status}")
|
||
print(f" Ответ сервера: {error_text}")
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"❌ Ошибка при отправке логов: {e}")
|
||
return False
|
||
|
||
def check_docker_services():
|
||
"""Проверка статуса Docker сервисов"""
|
||
print("🐳 Проверка статуса Docker сервисов...")
|
||
|
||
try:
|
||
# Проверяем статус контейнеров
|
||
result = subprocess.run(
|
||
['docker-compose', 'ps'],
|
||
capture_output=True,
|
||
text=True,
|
||
cwd='.'
|
||
)
|
||
|
||
if result.returncode == 0:
|
||
print("✅ Docker Compose сервисы:")
|
||
print(result.stdout)
|
||
return True
|
||
else:
|
||
print(f"❌ Ошибка проверки сервисов: {result.stderr}")
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"❌ Ошибка проверки Docker: {e}")
|
||
return False
|
||
|
||
def check_log_files():
|
||
"""Проверка создания логовых файлов"""
|
||
print("📁 Проверка логовых файлов...")
|
||
|
||
log_dir = "logs/remote"
|
||
if os.path.exists(log_dir):
|
||
files = os.listdir(log_dir)
|
||
if files:
|
||
print(f"✅ Найдены логовые файлы в {log_dir}:")
|
||
for file in files:
|
||
file_path = os.path.join(log_dir, file)
|
||
if os.path.isdir(file_path):
|
||
subfiles = os.listdir(file_path)
|
||
print(f" 📂 {file}/ ({len(subfiles)} файлов)")
|
||
for subfile in subfiles[:3]: # Показываем первые 3 файла
|
||
print(f" 📄 {subfile}")
|
||
if len(subfiles) > 3:
|
||
print(f" ... и еще {len(subfiles) - 3} файлов")
|
||
return True
|
||
else:
|
||
print(f"⚠️ Директория {log_dir} пуста")
|
||
return False
|
||
else:
|
||
print(f"❌ Директория {log_dir} не существует")
|
||
return False
|
||
|
||
async def test_client_communication():
|
||
"""Тестирование связи с клиентом"""
|
||
print("🔗 Тестирование связи с клиентом...")
|
||
|
||
try:
|
||
# Проверяем, запущен ли клиент
|
||
result = subprocess.run(
|
||
['docker-compose', 'ps', 'logboard-client'],
|
||
capture_output=True,
|
||
text=True,
|
||
cwd='.'
|
||
)
|
||
|
||
if 'Up' in result.stdout:
|
||
print("✅ LogBoard клиент запущен")
|
||
|
||
# Проверяем логи клиента
|
||
logs_result = subprocess.run(
|
||
['docker-compose', 'logs', '--tail=10', 'logboard-client'],
|
||
capture_output=True,
|
||
text=True,
|
||
cwd='.'
|
||
)
|
||
|
||
if logs_result.returncode == 0:
|
||
print("📋 Последние логи клиента:")
|
||
print(logs_result.stdout)
|
||
return True
|
||
else:
|
||
print("⚠️ Не удалось получить логи клиента")
|
||
return False
|
||
else:
|
||
print("❌ LogBoard клиент не запущен")
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"❌ Ошибка проверки клиента: {e}")
|
||
return False
|
||
|
||
async def main():
|
||
"""Основная функция тестирования"""
|
||
print("=" * 70)
|
||
print("LogBoard Remote System - Полное тестирование")
|
||
print("=" * 70)
|
||
print(f"Сервер: {SERVER_URL}")
|
||
print(f"API ключ: {API_KEY[:10]}..." if len(API_KEY) > 10 else f"API ключ: {API_KEY}")
|
||
print(f"Хост: {HOSTNAME}")
|
||
print()
|
||
|
||
tests = []
|
||
|
||
# Тест 1: Проверка Docker сервисов
|
||
print("1️⃣ Проверка Docker сервисов...")
|
||
docker_ok = check_docker_services()
|
||
tests.append(("Docker сервисы", docker_ok))
|
||
print()
|
||
|
||
# Тест 2: Проверка доступности сервера
|
||
print("2️⃣ Проверка доступности сервера...")
|
||
server_ok = await test_server_availability()
|
||
tests.append(("Доступность сервера", server_ok))
|
||
print()
|
||
|
||
if server_ok:
|
||
# Тест 3: Отправка тестовых логов
|
||
print("3️⃣ Отправка тестовых логов...")
|
||
logs_ok = await test_remote_logs_endpoint()
|
||
tests.append(("Отправка логов", logs_ok))
|
||
print()
|
||
|
||
# Тест 4: Проверка логовых файлов
|
||
print("4️⃣ Проверка логовых файлов...")
|
||
files_ok = check_log_files()
|
||
tests.append(("Логовые файлы", files_ok))
|
||
print()
|
||
|
||
# Тест 5: Проверка клиента
|
||
print("5️⃣ Проверка клиента...")
|
||
client_ok = await test_client_communication()
|
||
tests.append(("Связь с клиентом", client_ok))
|
||
print()
|
||
else:
|
||
print("⚠️ Пропуск тестов 3-5 из-за недоступности сервера")
|
||
tests.extend([
|
||
("Отправка логов", False),
|
||
("Логовые файлы", False),
|
||
("Связь с клиентом", False)
|
||
])
|
||
|
||
# Результаты тестирования
|
||
print("=" * 70)
|
||
print("РЕЗУЛЬТАТЫ ТЕСТИРОВАНИЯ")
|
||
print("=" * 70)
|
||
|
||
passed = 0
|
||
total = len(tests)
|
||
|
||
for test_name, result in tests:
|
||
status = "✅ ПРОЙДЕН" if result else "❌ НЕ ПРОЙДЕН"
|
||
print(f"{test_name:<20} {status}")
|
||
if result:
|
||
passed += 1
|
||
|
||
print()
|
||
print(f"Итого: {passed}/{total} тестов пройдено")
|
||
|
||
if passed == total:
|
||
print("🎉 Все тесты пройдены успешно!")
|
||
print(" Система удаленных клиентов работает корректно.")
|
||
elif passed >= total * 0.7:
|
||
print("⚠️ Большинство тестов пройдено.")
|
||
print(" Проверьте настройки для неудачных тестов.")
|
||
else:
|
||
print("❌ Много тестов не пройдено.")
|
||
print(" Проверьте конфигурацию и запуск сервисов.")
|
||
|
||
print()
|
||
print("Полезные команды:")
|
||
print(" make up - Запуск всех сервисов")
|
||
print(" make logs - Просмотр логов")
|
||
print(" make status - Статус сервисов")
|
||
print(" cd client && make test - Тестирование клиента")
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(main())
|