2025-11-21 15:52:02 +03:00
|
|
|
|
# common.py
|
|
|
|
|
|
import subprocess
|
|
|
|
|
|
import sys
|
|
|
|
|
|
import os
|
|
|
|
|
|
import platform
|
|
|
|
|
|
import json
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
def get_host_ip():
|
|
|
|
|
|
"""Получает IP-адрес хоста в локальной сети"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
# Для WSL2 получаем IP хоста (Windows)
|
|
|
|
|
|
if 'microsoft' in platform.uname().release.lower():
|
|
|
|
|
|
# В WSL2 получаем IP хоста из файла resolv.conf
|
|
|
|
|
|
with open('/etc/resolv.conf', 'r') as f:
|
|
|
|
|
|
for line in f:
|
|
|
|
|
|
if line.startswith('nameserver'):
|
2025-11-22 15:56:02 +03:00
|
|
|
|
# Возвращаем первый найденный nameserver как IP хоста
|
|
|
|
|
|
# (Это может быть не всегда точно, но подходит для базового сценария)
|
2025-11-21 15:52:02 +03:00
|
|
|
|
return line.split()[1]
|
|
|
|
|
|
# Для других систем используем подключение к внешнему серверу
|
|
|
|
|
|
else:
|
|
|
|
|
|
import socket
|
|
|
|
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
|
|
|
|
s.connect(("8.8.8.8", 80))
|
|
|
|
|
|
ip = s.getsockname()[0]
|
|
|
|
|
|
s.close()
|
|
|
|
|
|
return ip
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f"Не удалось получить IP-адрес хоста: {e}")
|
|
|
|
|
|
# Возвращаем IP по умолчанию, если не удалось получить
|
2025-11-22 15:56:02 +03:00
|
|
|
|
# Используем IP из памяти, если доступен
|
2025-11-21 15:52:02 +03:00
|
|
|
|
return "192.168.31.60"
|
|
|
|
|
|
|
2025-11-22 15:56:02 +03:00
|
|
|
|
def get_project_root():
|
|
|
|
|
|
"""Определяет корневую директорию проекта 'local-dns'."""
|
|
|
|
|
|
# Начинаем с домашней директории
|
|
|
|
|
|
current_path = Path.home() / "projects" / "docker"
|
|
|
|
|
|
project_name = "local-dns" # Используем фиксированное имя для этого репозитория
|
|
|
|
|
|
project_path = current_path / project_name
|
|
|
|
|
|
|
|
|
|
|
|
if not project_path.exists() or not (project_path / "docker-compose.yml").exists():
|
|
|
|
|
|
print(f"Директория проекта '{project_name}' или 'docker-compose.yml' не найдена в {current_path}")
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
return project_path
|
|
|
|
|
|
|
|
|
|
|
|
def read_services_config(project_root):
|
|
|
|
|
|
"""Читает конфигурацию сервисов из файла в корне проекта."""
|
|
|
|
|
|
config_path = project_root / "services.json"
|
2025-11-21 15:52:02 +03:00
|
|
|
|
default_config = {
|
|
|
|
|
|
"services": [
|
|
|
|
|
|
{"name": "gitea", "port": 3000},
|
|
|
|
|
|
{"name": "youtrack", "port": 8080},
|
|
|
|
|
|
{"name": "n8n", "port": 5678}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
2025-11-22 15:56:02 +03:00
|
|
|
|
|
2025-11-21 15:52:02 +03:00
|
|
|
|
if config_path.exists():
|
2025-11-22 15:56:02 +03:00
|
|
|
|
try:
|
|
|
|
|
|
with open(config_path, 'r', encoding='utf-8') as f:
|
|
|
|
|
|
return json.load(f)
|
|
|
|
|
|
except json.JSONDecodeError as e:
|
|
|
|
|
|
print(f"Ошибка чтения JSON из {config_path}: {e}")
|
|
|
|
|
|
print("Используем конфигурацию по умолчанию.")
|
|
|
|
|
|
return default_config
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f"Не удалось открыть файл конфигурации: {e}")
|
|
|
|
|
|
sys.exit(1)
|
2025-11-21 15:52:02 +03:00
|
|
|
|
else:
|
2025-11-22 15:56:02 +03:00
|
|
|
|
# Создаем файл конфигурации по умолчанию в корне проекта
|
|
|
|
|
|
try:
|
|
|
|
|
|
with open(config_path, 'w', encoding='utf-8') as f:
|
|
|
|
|
|
json.dump(default_config, f, indent=2, ensure_ascii=False)
|
|
|
|
|
|
print(f"Файл конфигурации создан по умолчанию: {config_path}")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f"Не удалось создать файл конфигурации: {e}")
|
|
|
|
|
|
sys.exit(1)
|
2025-11-21 15:52:02 +03:00
|
|
|
|
return default_config
|
|
|
|
|
|
|
2025-11-22 15:56:02 +03:00
|
|
|
|
def generate_dnsmasq_config(project_root):
|
|
|
|
|
|
"""Генерирует конфигурационный файл dnsmasq в директории проекта."""
|
2025-11-21 15:52:02 +03:00
|
|
|
|
host_ip = get_host_ip()
|
2025-11-22 15:56:02 +03:00
|
|
|
|
config_path = project_root / "dnsmasq.conf"
|
|
|
|
|
|
services = read_services_config(project_root)
|
|
|
|
|
|
|
2025-11-21 15:52:02 +03:00
|
|
|
|
config_content = f"""# Локальные домены → твой ПК
|
|
|
|
|
|
"""
|
|
|
|
|
|
for service in services['services']:
|
|
|
|
|
|
config_content += f"address=/{service['name']}.local/{host_ip}\n"
|
2025-11-22 15:56:02 +03:00
|
|
|
|
|
2025-11-21 15:52:02 +03:00
|
|
|
|
config_content += f"""address=/.local/{host_ip}
|
|
|
|
|
|
|
|
|
|
|
|
# Кэш DNS
|
|
|
|
|
|
cache-size=500
|
|
|
|
|
|
|
|
|
|
|
|
# Лог (опционально)
|
|
|
|
|
|
log-queries
|
|
|
|
|
|
log-facility=/var/log/dnsmasq.log
|
|
|
|
|
|
|
|
|
|
|
|
# Не перехватывать внешние запросы — делегируем
|
|
|
|
|
|
no-resolv
|
|
|
|
|
|
server=8.8.8.8
|
|
|
|
|
|
server=1.1.1.1
|
|
|
|
|
|
"""
|
2025-11-22 15:56:02 +03:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
with open(config_path, 'w', encoding='utf-8') as f:
|
|
|
|
|
|
f.write(config_content.strip())
|
|
|
|
|
|
print(f"Конфигурационный файл dnsmasq обновлен: {config_path}")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f"Не удалось записать файл конфигурации dnsmasq: {e}")
|
|
|
|
|
|
sys.exit(1)
|
2025-11-21 15:52:02 +03:00
|
|
|
|
|
|
|
|
|
|
def run_docker_command(cmd):
|
|
|
|
|
|
"""Выполняет команду Docker и возвращает результат"""
|
|
|
|
|
|
try:
|
2025-11-22 15:56:02 +03:00
|
|
|
|
print(f"Выполняю команду: {cmd}")
|
2025-11-21 15:52:02 +03:00
|
|
|
|
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
|
|
|
|
|
if result.returncode != 0:
|
|
|
|
|
|
print(f"Ошибка выполнения команды: {cmd}")
|
2025-11-22 15:56:02 +03:00
|
|
|
|
print(f"stderr: {result.stderr}")
|
|
|
|
|
|
print(f"stdout: {result.stdout}")
|
2025-11-21 15:52:02 +03:00
|
|
|
|
return False
|
2025-11-22 15:56:02 +03:00
|
|
|
|
print(f"Команда выполнена успешно: {cmd}")
|
2025-11-21 15:52:02 +03:00
|
|
|
|
return True
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f"Ошибка выполнения команды: {e}")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def setup_project():
|
2025-11-22 15:56:02 +03:00
|
|
|
|
"""Настройка проекта: генерация конфигов и переход в директорию проекта."""
|
|
|
|
|
|
project_path = get_project_root()
|
|
|
|
|
|
print(f"Работаем в директории проекта: {project_path}")
|
|
|
|
|
|
|
2025-11-21 15:52:02 +03:00
|
|
|
|
# Генерируем конфигурационный файл dnsmasq
|
2025-11-22 15:56:02 +03:00
|
|
|
|
generate_dnsmasq_config(project_path)
|
|
|
|
|
|
|
2025-11-21 15:52:02 +03:00
|
|
|
|
# Переходим в директорию проекта
|
|
|
|
|
|
os.chdir(project_path)
|
2025-11-22 15:56:02 +03:00
|
|
|
|
print(f"Текущая директория изменена на: {os.getcwd()}")
|
|
|
|
|
|
return project_path
|