""" main """ import subprocess import logging import argparse from pathlib import Path import yaml from src.logger import get_logger from src.nginx import NginxConfig, NginxConfigurator logger = get_logger(__name__) # 配置常量 FILE_PATH = Path(__file__).parent DOCKER_COMPOSE_FILE = Path(FILE_PATH, "docker-compose.yml") NETWORK_NAME = "nginx-net" def validate_docker_network(): """检查Docker网络是否存在""" try: result = subprocess.run( ["docker", "network", "inspect", NETWORK_NAME], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True ) return result.returncode == 0 except subprocess.CalledProcessError: logger.error("Docker网络 %s 不存在", NETWORK_NAME) return False except Exception as e: logger.error("网络检查异常: %s", str(e), exc_info=True) return False def parse_compose_config(file_path: Path) -> list[NginxConfig]: """解析Docker Compose文件""" try: with open(file_path, 'r', encoding='utf-8') as f: config = yaml.safe_load(f) services:dict = config['services'] # networks = config['networks'][NETWORK_NAME] # if not networks['external']: # raise ValueError("network 必须为external") nginx_configs:list[NginxConfig] = [] for name, service in services.items(): try: labels = service.get('labels') if labels is not None: n = labels.get('nginx_prefix_name') if n is not None: name = n conf = NginxConfig( name = f"{name}.zzyxyz.com", host = service['container_name'], port = service['expose'][0] ) if len(service['expose']) != 1: raise ValueError("expose 必须为一项") networks = service.get('networks') # TODO if networks is None or networks[0] != NETWORK_NAME: raise ValueError(f"networks 需要设置为{NETWORK_NAME}") # required_fields = ['com.lingma.nginx.domain', 'com.lingma.nginx.port'] # for field in required_fields: # if field not in labels: # raise ValueError(f"服务 {name} 缺少必要标签: {field}") nginx_configs.append(conf) except Exception as e: logger.error("解析服务 %s 配置失败: %s{str(e)}", name, str(e)) continue return nginx_configs except FileNotFoundError: logger.error("文件不存在: %s", file_path) return False except PermissionError: logger.error("无权限访问文件: %s", file_path) return False except yaml.YAMLError as e: logger.error("YAML解析错误: %s", str(e)) return False except Exception as e: logger.error("未知错误: %s", str(e), exc_info=True) return False def main(): """main""" parser = argparse.ArgumentParser(description="Nginx自动化配置工具") parser.add_argument('--compose-file', type=str, default=DOCKER_COMPOSE_FILE, help="Docker Compose文件路径") parser.add_argument('--debug', action='store_true', help="启用调试模式") args = parser.parse_args() if args.debug: logger.setLevel(logging.DEBUG) logger.debug("调试模式已启用") # 前置检查 if not validate_docker_network(): logger.error("请先创建Docker网络: docker network create %s", NETWORK_NAME) return # 配置生成 try: logger.info("开始解析Docker Compose配置...") compose_files:str = args.compose_file configs = [] for file in compose_files.split(','): logger.info("parse %s", file) config = parse_compose_config(file) configs.extend(config) logger.info("发现 %d 个需要代理的服务", len(configs)) conf = NginxConfigurator() conf.backup_config() ret = conf.gen_and_save_config(configs) if not ret: return ret = conf.safe_reload() if ret: logger.info("全流程完成") else: logger.error("流程未完成,请检查错误日志") except Exception as e: logger.critical("主流程异常终止: %s", str(e), exc_info=args.debug) if __name__ == "__main__": main()