diff --git a/backend/app/services/scheduler/schedule_tenant.py b/backend/app/services/scheduler/schedule_tenant.py index 3ccb578..8b025fc 100644 --- a/backend/app/services/scheduler/schedule_tenant.py +++ b/backend/app/services/scheduler/schedule_tenant.py @@ -19,7 +19,8 @@ from app.models.result import TenantScheduleResult logger = logging.getLogger(__name__) -PG_PORT = 5433 +PG_PORT_TRIAL = 5433 +PG_PORT_ACTIVE = 5432 PG_USER = "admin" PG_PASS = "DC1qaz2wsx" PG_HOST_TRIAL = "10.1.0.20" @@ -56,6 +57,7 @@ def _generate_tenant_compose(tenant, is_active: bool) -> str: nc = f"nc-{code}{suffix}" oo = f"oo-{code}{suffix}" pg_host = PG_HOST_ACTIVE if is_active else PG_HOST_TRIAL + pg_port = PG_PORT_ACTIVE if is_active else PG_PORT_TRIAL pg_db = f"nc_{code}_db" nc_domain = tenant.domain oo_host = f"office-{code}.ease.taipei" if is_active else f"office-{code}.lab.taipei" @@ -73,7 +75,7 @@ def _generate_tenant_compose(tenant, is_active: bool) -> str: - {nc}-apps:/var/www/html/custom_apps - {nc}-config:/var/www/html/config environment: - POSTGRES_HOST: {pg_host}:{PG_PORT} + POSTGRES_HOST: {pg_host}:{pg_port} POSTGRES_DB: {pg_db} POSTGRES_USER: {PG_USER} POSTGRES_PASSWORD: ${{NC_DB_PASSWORD}} @@ -372,7 +374,7 @@ def _ensure_kc_drive_client(realm: str, domain: str) -> Optional[str]: return None -def _nc_db_check(container_name: str, pg_host: str, pg_db: str, nc_domain: str) -> bool: +def _nc_db_check(container_name: str, pg_host: str, pg_db: str, nc_domain: str, pg_port: int = PG_PORT_TRIAL) -> bool: """ 驗證 NC 是否正確安裝並使用 PostgreSQL。 若偵測到 SQLite(常見於 volumes 持久但重新部署的情況),自動修復: @@ -406,7 +408,7 @@ def _nc_db_check(container_name: str, pg_host: str, pg_db: str, nc_domain: str) logger.info(f"NC {container_name}: not installed yet, installing with pgsql...") # 重置 PostgreSQL DB schema(確保乾淨狀態) conn = psycopg2.connect( - host=pg_host, port=PG_PORT, dbname=pg_db, + host=pg_host, port=pg_port, dbname=pg_db, user=PG_USER, password=PG_PASS, connect_timeout=5, ) conn.autocommit = True @@ -420,7 +422,7 @@ def _nc_db_check(container_name: str, pg_host: str, pg_db: str, nc_domain: str) f"-n --admin-user admin --admin-pass NC1qaz2wsx " f"--database pgsql --database-name '{pg_db}' " f"--database-user {PG_USER} --database-pass {PG_PASS} " - f"--database-host '{pg_host}:{PG_PORT}' 2>&1" + f"--database-host '{pg_host}:{pg_port}' 2>&1" ) _, stdout_inst, _ = client.exec_command(install_cmd) stdout_inst.channel.settimeout(120) @@ -481,7 +483,7 @@ def _nc_db_check(container_name: str, pg_host: str, pg_db: str, nc_domain: str) # 2. 重置 PostgreSQL DB schema conn = psycopg2.connect( - host=pg_host, port=PG_PORT, dbname=pg_db, + host=pg_host, port=pg_port, dbname=pg_db, user=PG_USER, password=PG_PASS, connect_timeout=5, ) conn.autocommit = True @@ -496,7 +498,7 @@ def _nc_db_check(container_name: str, pg_host: str, pg_db: str, nc_domain: str) f"-n --admin-user admin --admin-pass NC1qaz2wsx " f"--database pgsql --database-name '{pg_db}' " f"--database-user {PG_USER} --database-pass {PG_PASS} " - f"--database-host '{pg_host}:{PG_PORT}' 2>&1" + f"--database-host '{pg_host}:{pg_port}' 2>&1" ) _, stdout3, _ = client2.exec_command(install_cmd) stdout3.channel.recv_exit_status() @@ -721,7 +723,7 @@ def _configure_nc_oidc( # ─── PostgreSQL helpers ─────────────────────────────────────────────────────── -def _ensure_nc_db(host: str, dbname: str) -> bool: +def _ensure_nc_db(host: str, dbname: str, port: int = PG_PORT_TRIAL) -> bool: """ 確保 NC 用的 PostgreSQL DB 存在,並授予 public schema 建表權限給所有用戶。 NC Docker 會自動建立 oc_admin* 用戶,需預先開放 public schema CREATE 權限。 @@ -730,7 +732,7 @@ def _ensure_nc_db(host: str, dbname: str) -> bool: import psycopg2 # Connect to postgres DB to create NC DB conn = psycopg2.connect( - host=host, port=PG_PORT, dbname="postgres", + host=host, port=port, dbname="postgres", user=PG_USER, password=PG_PASS, connect_timeout=5, ) @@ -744,7 +746,7 @@ def _ensure_nc_db(host: str, dbname: str) -> bool: # Grant CREATE on public schema to all users (for NC oc_admin* users) conn2 = psycopg2.connect( - host=host, port=PG_PORT, dbname=dbname, + host=host, port=port, dbname=dbname, user=PG_USER, password=PG_PASS, connect_timeout=5, ) @@ -758,11 +760,11 @@ def _ensure_nc_db(host: str, dbname: str) -> bool: return False -def _get_pg_db_size_gb(host: str, dbname: str) -> Optional[float]: +def _get_pg_db_size_gb(host: str, dbname: str, port: int = PG_PORT_TRIAL) -> Optional[float]: try: import psycopg2 conn = psycopg2.connect( - host=host, port=PG_PORT, dbname=dbname, + host=host, port=port, dbname=dbname, user=PG_USER, password=PG_PASS, connect_timeout=5, ) @@ -849,6 +851,7 @@ def run_tenant_check(schedule_log_id: int, db: Session): oo_name = f"oo-{tenant.code}" if is_active else f"oo-{tenant.code}-test" kc_host = KC_HOST_ACTIVE if is_active else KC_HOST_TRIAL pg_host = PG_HOST_ACTIVE if is_active else PG_HOST_TRIAL + pg_port = PG_PORT_ACTIVE if is_active else PG_PORT_TRIAL result = TenantScheduleResult( schedule_log_id=schedule_log_id, @@ -932,14 +935,14 @@ def run_tenant_check(schedule_log_id: int, db: Session): # 容器不存在 → 確保 docker-compose.yml + DB + 部署 logger.info(f"NC {nc_name}: not found, ensuring compose/DB and deploying") _ensure_tenant_compose(tenant, is_active) - _ensure_nc_db(pg_host, pg_db) + _ensure_nc_db(pg_host, pg_db, pg_port) ok = docker.ssh_compose_up(tenant.code) result.nc_result = True if ok else False if not ok: fail_reasons.append("nc: deploy failed") else: # 部署成功後驗證 NC 是否正確使用 PostgreSQL - if not _nc_db_check(nc_name, pg_host, pg_db, tenant.domain): + if not _nc_db_check(nc_name, pg_host, pg_db, tenant.domain, pg_port): result.nc_result = False fail_reasons.append("nc: installed but not using pgsql") elif nc_state is False: @@ -951,7 +954,7 @@ def run_tenant_check(schedule_log_id: int, db: Session): fail_reasons.append("nc: start failed") else: # 容器正常運行 → 驗證 DB 類型(防止 sqlite3 殘留問題) - db_ok = _nc_db_check(nc_name, pg_host, pg_db, tenant.domain) + db_ok = _nc_db_check(nc_name, pg_host, pg_db, tenant.domain, pg_port) if not db_ok: result.nc_result = False fail_reasons.append("nc: DB check failed (possible sqlite3 issue)") @@ -1001,7 +1004,7 @@ def run_tenant_check(schedule_log_id: int, db: Session): # ── [6] Quota (OO disk + PG DB size) ──────────────────────────────── try: oo_gb = docker.get_oo_disk_usage_gb(oo_name) or 0.0 - pg_gb = _get_pg_db_size_gb(pg_host, pg_db) or 0.0 + pg_gb = _get_pg_db_size_gb(pg_host, pg_db, pg_port) or 0.0 result.quota_usage = round(oo_gb + pg_gb, 3) except Exception as e: logger.warning(f"Quota check failed for {tenant.code}: {e}")