Обновлено форматирование даты в логах на DD.MM.YYYY для скриптов и хуков
This commit is contained in:
83
Makefile
83
Makefile
@@ -103,11 +103,33 @@ setup-dirs:
|
||||
# Установка зависимостей
|
||||
install-dependencies:
|
||||
@echo "$(YELLOW)→ Установка зависимостей Python...$(NC)"
|
||||
@if ! command -v pip3 >/dev/null 2>&1; then \
|
||||
echo "$(RED)✗ pip3 не найден. Установите python3-pip$(NC)"; \
|
||||
@if command -v pip3 >/dev/null 2>&1; then \
|
||||
pip3 install -q requests cryptography 2>/dev/null || pip3 install requests cryptography; \
|
||||
elif command -v pip >/dev/null 2>&1; then \
|
||||
pip install -q requests cryptography 2>/dev/null || pip install requests cryptography; \
|
||||
elif command -v python3 >/dev/null 2>&1; then \
|
||||
if python3 -m pip --version >/dev/null 2>&1; then \
|
||||
python3 -m pip install -q requests cryptography 2>/dev/null || python3 -m pip install requests cryptography; \
|
||||
else \
|
||||
echo "$(RED)✗ pip не установлен. Выполните:$(NC)"; \
|
||||
echo " $(CYAN)sudo apt-get update && sudo apt-get install -y python3-pip$(NC)"; \
|
||||
echo " или"; \
|
||||
echo " $(CYAN)curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python3 get-pip.py$(NC)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
elif command -v python >/dev/null 2>&1; then \
|
||||
if python -m pip --version >/dev/null 2>&1; then \
|
||||
python -m pip install -q requests cryptography 2>/dev/null || python -m pip install requests cryptography; \
|
||||
else \
|
||||
echo "$(RED)✗ pip не установлен. Выполните:$(NC)"; \
|
||||
echo " $(CYAN)sudo apt-get update && sudo apt-get install -y python3-pip$(NC)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
else \
|
||||
echo "$(RED)✗ Python не найден. Установите Python 3:$(NC)"; \
|
||||
echo " $(CYAN)sudo apt-get update && sudo apt-get install -y python3 python3-pip$(NC)"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@pip3 install -q requests cryptography 2>/dev/null || pip3 install requests cryptography
|
||||
@echo "$(GREEN)✓ Зависимости установлены$(NC)"
|
||||
|
||||
# Копирование скрипта
|
||||
@@ -193,17 +215,20 @@ uninstall: check-root
|
||||
@echo "$(RED)║ Удаление Let's Encrypt SSL Manager ║$(NC)"
|
||||
@echo "$(RED)╚════════════════════════════════════════════════════════════════╝$(NC)"
|
||||
@echo ""
|
||||
@read -p "Вы уверены? Это удалит все файлы и настройки [y/N]: " -n 1 -r; \
|
||||
echo ""; \
|
||||
if [[ $$REPLY =~ ^[Yy]$$ ]]; then \
|
||||
@printf "Вы уверены? Это удалит все файлы и настройки [y/N]: "; \
|
||||
read REPLY; \
|
||||
case "$$REPLY" in \
|
||||
[Yy]* ) \
|
||||
$(MAKE) remove-service; \
|
||||
$(MAKE) remove-cron; \
|
||||
$(MAKE) remove-files; \
|
||||
echo ""; \
|
||||
echo "$(GREEN)✓ Удаление завершено$(NC)"; \
|
||||
else \
|
||||
;; \
|
||||
* ) \
|
||||
echo "$(YELLOW)Удаление отменено$(NC)"; \
|
||||
fi
|
||||
;; \
|
||||
esac
|
||||
|
||||
# Удаление systemd service
|
||||
remove-service:
|
||||
@@ -229,23 +254,29 @@ remove-files:
|
||||
@rm -rf $(INSTALL_DIR)
|
||||
@echo "$(GREEN)✓ Директория $(INSTALL_DIR) удалена$(NC)"
|
||||
@echo ""
|
||||
@read -p "Удалить конфигурацию $(CONFIG_FILE)? [y/N]: " -n 1 -r; \
|
||||
echo ""; \
|
||||
if [[ $$REPLY =~ ^[Yy]$$ ]]; then \
|
||||
@printf "Удалить конфигурацию $(CONFIG_FILE)? [y/N]: "; \
|
||||
read REPLY; \
|
||||
case "$$REPLY" in \
|
||||
[Yy]* ) \
|
||||
rm -f $(CONFIG_FILE); \
|
||||
echo "$(GREEN)✓ Конфигурация удалена$(NC)"; \
|
||||
else \
|
||||
;; \
|
||||
* ) \
|
||||
echo "$(YELLOW)Конфигурация сохранена$(NC)"; \
|
||||
fi
|
||||
;; \
|
||||
esac
|
||||
@echo ""
|
||||
@read -p "Удалить логи? [y/N]: " -n 1 -r; \
|
||||
echo ""; \
|
||||
if [[ $$REPLY =~ ^[Yy]$$ ]]; then \
|
||||
@printf "Удалить логи? [y/N]: "; \
|
||||
read REPLY; \
|
||||
case "$$REPLY" in \
|
||||
[Yy]* ) \
|
||||
rm -f $(LOG_FILE) $(CRON_LOG); \
|
||||
echo "$(GREEN)✓ Логи удалены$(NC)"; \
|
||||
else \
|
||||
;; \
|
||||
* ) \
|
||||
echo "$(YELLOW)Логи сохранены$(NC)"; \
|
||||
fi
|
||||
;; \
|
||||
esac
|
||||
|
||||
# ==============================================================================
|
||||
# Утилиты
|
||||
@@ -301,12 +332,24 @@ check-config:
|
||||
@echo ""
|
||||
@if [ ! -f "$(CONFIG_FILE)" ]; then \
|
||||
echo "$(RED)✗ Конфигурация не найдена: $(CONFIG_FILE)$(NC)"; \
|
||||
echo "$(YELLOW)Совет: Скопируйте config.json.example в $(CONFIG_FILE)$(NC)"; \
|
||||
echo " $(CYAN)sudo cp config.json.example $(CONFIG_FILE)$(NC)"; \
|
||||
echo " $(CYAN)sudo chmod 644 $(CONFIG_FILE)$(NC)"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "$(GREEN)✓ Конфигурация найдена$(NC)"
|
||||
@if [ ! -r "$(CONFIG_FILE)" ]; then \
|
||||
echo "$(RED)✗ Нет прав для чтения: $(CONFIG_FILE)$(NC)"; \
|
||||
echo "$(YELLOW)Решение: Запустите команду с sudo:$(NC)"; \
|
||||
echo " $(CYAN)sudo make check-config$(NC)"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo ""
|
||||
@$(PYTHON) -c "import json; print(json.dumps(json.load(open('$(CONFIG_FILE)')), indent=2, ensure_ascii=False))" 2>/dev/null || \
|
||||
(echo "$(RED)✗ Ошибка: Неверный формат JSON$(NC)"; exit 1)
|
||||
@$(PYTHON) -c "import json; print(json.dumps(json.load(open('$(CONFIG_FILE)')), indent=2, ensure_ascii=False))" 2>&1 || \
|
||||
(echo "$(RED)✗ Ошибка: Неверный формат JSON$(NC)"; \
|
||||
echo "$(YELLOW)Подробности:$(NC)"; \
|
||||
$(PYTHON) -c "import json; json.load(open('$(CONFIG_FILE)'))" 2>&1 | head -5; \
|
||||
exit 1)
|
||||
@echo ""
|
||||
@echo "$(YELLOW)→ Проверка обязательных параметров:$(NC)"
|
||||
@$(PYTHON) -c "import json; c=json.load(open('$(CONFIG_FILE)')); assert c.get('regru_username'), 'regru_username не задан'" && echo " $(GREEN)✓ regru_username$(NC)" || echo " $(RED)✗ regru_username$(NC)"
|
||||
|
||||
@@ -28,7 +28,7 @@ NC='\033[0m' # No Color
|
||||
# Функция логирования
|
||||
# ==============================================================================
|
||||
log() {
|
||||
echo -e "${2:-$NC}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}" | tee -a "$LOG_FILE"
|
||||
echo -e "${2:-$NC}[$(date +'%d.%m.%Y %H:%M:%S')] $1${NC}" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
|
||||
@@ -115,7 +115,7 @@ def setup_logging(log_file: str, verbose: bool = False) -> logging.Logger:
|
||||
# Настройка форматирования
|
||||
formatter = logging.Formatter(
|
||||
'%(asctime)s - %(levelname)s - %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
datefmt='%d.%m.%Y %H:%M:%S'
|
||||
)
|
||||
|
||||
# Создаем logger
|
||||
@@ -406,6 +406,10 @@ class NginxProxyManagerAPI:
|
||||
"""
|
||||
Загрузка нового сертификата в NPM
|
||||
|
||||
ВАЖНО: NPM автоматически извлекает информацию из сертификата.
|
||||
Мы загружаем сертификат через веб-интерфейс формы (multipart/form-data),
|
||||
а не через JSON API, так как JSON endpoint имеет строгую валидацию схемы.
|
||||
|
||||
Args:
|
||||
domain: Основной домен
|
||||
cert_path: Путь к файлу сертификата
|
||||
@@ -425,29 +429,36 @@ class NginxProxyManagerAPI:
|
||||
with open(key_path, 'r') as f:
|
||||
certificate_key = f.read()
|
||||
|
||||
# Если есть цепочка, объединяем с сертификатом
|
||||
# Используем промежуточный сертификат если доступен
|
||||
intermediate_certificate = ""
|
||||
if chain_path and os.path.exists(chain_path):
|
||||
with open(chain_path, 'r') as f:
|
||||
chain = f.read()
|
||||
# NPM ожидает fullchain (cert + chain)
|
||||
certificate = certificate + "\n" + chain
|
||||
intermediate_certificate = f.read()
|
||||
|
||||
# Формируем payload для API
|
||||
payload = {
|
||||
"provider": "other",
|
||||
"nice_name": f"{domain} - Let's Encrypt",
|
||||
"domain_names": [domain],
|
||||
"certificate": certificate,
|
||||
"certificate_key": certificate_key,
|
||||
"meta": {
|
||||
"letsencrypt_agree": True,
|
||||
"dns_challenge": True,
|
||||
"dns_provider": "reg_ru"
|
||||
}
|
||||
# NPM Web UI использует multipart/form-data для загрузки custom сертификатов
|
||||
# Эмулируем загрузку через веб-форму
|
||||
files = {
|
||||
'certificate': ('cert.pem', certificate, 'application/x-pem-file'),
|
||||
'certificate_key': ('privkey.pem', certificate_key, 'application/x-pem-file'),
|
||||
}
|
||||
|
||||
# Добавляем промежуточный сертификат если есть
|
||||
if intermediate_certificate:
|
||||
files['intermediate_certificate'] = ('chain.pem', intermediate_certificate, 'application/x-pem-file')
|
||||
|
||||
# Дополнительные поля формы
|
||||
data = {
|
||||
'nice_name': domain,
|
||||
'provider': 'other', # Обязательное поле: 'letsencrypt' или 'other'
|
||||
}
|
||||
|
||||
self.logger.debug(f"Uploading certificate as multipart/form-data")
|
||||
self.logger.debug(f"Files: {list(files.keys())}")
|
||||
self.logger.debug(f"Data: {data}")
|
||||
self.logger.info(f"Загрузка сертификата для {domain} в NPM...")
|
||||
response = self.session.post(url, json=payload, timeout=30)
|
||||
|
||||
# Отправляем как multipart/form-data
|
||||
response = self.session.post(url, files=files, data=data, timeout=30)
|
||||
response.raise_for_status()
|
||||
|
||||
result = response.json()
|
||||
@@ -493,20 +504,29 @@ class NginxProxyManagerAPI:
|
||||
with open(key_path, 'r') as f:
|
||||
certificate_key = f.read()
|
||||
|
||||
# Если есть цепочка, объединяем с сертификатом
|
||||
# Используем промежуточный сертификат если доступен
|
||||
intermediate_certificate = ""
|
||||
if chain_path and os.path.exists(chain_path):
|
||||
with open(chain_path, 'r') as f:
|
||||
chain = f.read()
|
||||
certificate = certificate + "\n" + chain
|
||||
intermediate_certificate = f.read()
|
||||
|
||||
# Формируем payload для обновления
|
||||
payload = {
|
||||
"certificate": certificate,
|
||||
"certificate_key": certificate_key
|
||||
# NPM Web UI использует multipart/form-data для обновления
|
||||
files = {
|
||||
'certificate': ('cert.pem', certificate, 'application/x-pem-file'),
|
||||
'certificate_key': ('privkey.pem', certificate_key, 'application/x-pem-file'),
|
||||
}
|
||||
|
||||
# Добавляем промежуточный сертификат если есть
|
||||
if intermediate_certificate:
|
||||
files['intermediate_certificate'] = ('chain.pem', intermediate_certificate, 'application/x-pem-file')
|
||||
|
||||
# Дополнительные поля формы
|
||||
data = {
|
||||
'provider': 'other', # Обязательное поле
|
||||
}
|
||||
|
||||
self.logger.info(f"Обновление сертификата ID {cert_id} в NPM...")
|
||||
response = self.session.put(url, json=payload, timeout=30)
|
||||
response = self.session.put(url, files=files, data=data, timeout=30)
|
||||
response.raise_for_status()
|
||||
|
||||
self.logger.info("Сертификат успешно обновлен в NPM")
|
||||
@@ -813,7 +833,7 @@ class LetsEncryptManager:
|
||||
expiry_date = cert.not_valid_after
|
||||
days_left = (expiry_date - datetime.now()).days
|
||||
|
||||
self.logger.info(f"Сертификат истекает: {expiry_date.strftime('%Y-%m-%d')}")
|
||||
self.logger.info(f"Сертификат истекает: {expiry_date.strftime('%d.%m.%Y %H:%M:%S')}")
|
||||
self.logger.info(f"Осталось дней: {days_left}")
|
||||
|
||||
return days_left
|
||||
|
||||
Reference in New Issue
Block a user