diff --git a/conf/aether_api_config.py b/conf/aether_api_config.py index 94e6927..f7aa021 100644 --- a/conf/aether_api_config.py +++ b/conf/aether_api_config.py @@ -1,93 +1,55 @@ # Configuration file for this FastAPI app. import os -from pydantic import AnyHttpUrl, BaseSettings, EmailStr, HttpUrl, PostgresDsn, validator +from pydantic import BaseSettings from typing import Any, Dict, List, Optional, Union - -# ### ### # - - class Settings(BaseSettings): - AETHER_CFG = {} - AETHER_CFG['id'] = os.getenv('AE_CFG_ID', None) - # AETHER_CFG['api_id'] = os.getenv('AE_API_CFG_ID', None) # NOT CURRENTLY NEED OR USED + AETHER_CFG: Dict[str, Any] = { + "id": os.getenv('AE_CFG_ID', '0') + } - JWT_KEY = os.getenv('AE_API_JWT_KEY', '22 chars 00xXyYzZ99') # 22 characters; super secret Aether JWT signing key - - # APP_NAME: str = "Aether API (FastAPI)" - # SUPER_EMAIL: EmailStr = 'Aether.Super@oneskyit.com' - + JWT_KEY: str = os.getenv('AE_API_JWT_KEY', 'EHmSXZFKfMEW65E8kxCKmQ') # Database Connection - DB = {} - DB['server'] = os.getenv('AE_DB_SERVER', 'mariadb') # 'linode.oneskyit.com' # linode.oneskyit.com, vpn-linode linode.oneskyit.local - DB['port'] = os.getenv('AE_DB_PORT', '3306') # default = 3306 - DB['name'] = os.getenv('AE_DB_NAME', None) # 'aether_dev' #onesky_ams_dev - DB['username'] = os.getenv('AE_DB_USERNAME', None) # 'osit_aether' # 'onesky_aether' - DB['password'] = os.getenv('AE_DB_PASSWORD', None) # - SQLALCHEMY_DB_URI = 'mysql://'+DB['username']+':'+DB['password']+'@'+DB['server']+'/'+DB['name'] - - # DB['wait_timeout'] = int(os.getenv('AE_DB_WAIT_TIMEOUT', 1800)) # Not used yet! default = 28800; Time (seconds) that the server waits for a connection to become active before closing it. - DB['connect_timeout'] = int(os.getenv('AE_DB_CONNECTION_TIMEOUT', 20)) # default = 10; Time (seconds) that the server waits for a connection to become active before closing it. - DB['pool_recycle'] = int(os.getenv('AE_DB_POOL_RECYCLE', 1800)) # default = ?; Related to SQLAlchemy + # We use first-level attributes so BaseSettings can map them automatically if needed, + # but we keep the DB dictionary structure for compatibility with the rest of the app. + DB_SERVER: str = os.getenv('AE_DB_SERVER', 'mariadb') + DB_PORT: str = os.getenv('AE_DB_PORT', '3306') + DB_NAME: str = os.getenv('AE_DB_NAME', 'aether_dev') + DB_USER: str = os.getenv('AE_DB_USERNAME', 'aether_dev') + DB_PASS: str = os.getenv('AE_DB_PASSWORD', '') + @property + def SQLALCHEMY_DB_URI(self) -> str: + # Use a property to ensure the URI is built dynamically and safely + return f"mysql://{self.DB_USER}:{self.DB_PASS}@{self.DB_SERVER}:{self.DB_PORT}/{self.DB_NAME}" - # Aether API log files paths - LOG_PATH = {} - LOG_PATH['app'] = os.getenv('AE_API_LOG_PATH', 'admin/log/app.log') # 'admin/log/app.log', '../../logs/aether_api.log' - # LOG_PATH['app_warning'] = '/logs/aether_api_warning.log' # 'admin/log/app_warning.log' '../../logs/aether_api_warning.log' + @property + def DB(self) -> Dict[str, Any]: + # Compatibility dictionary + return { + "server": self.DB_SERVER, + "port": self.DB_PORT, + "name": self.DB_NAME, + "username": self.DB_USER, + "password": self.DB_PASS, + "connect_timeout": int(os.getenv('AE_DB_CONNECTION_TIMEOUT', 20)), + "pool_recycle": int(os.getenv('AE_DB_POOL_RECYCLE', 1800)) + } + # Logging + LOG_PATH: Dict[str, str] = { + "app": os.getenv('AE_API_LOG_PATH', '/logs/aether_api.log') + } # Redis - REDIS = {} - REDIS['server'] = os.getenv('AE_REDIS_SERVER', 'redis') # 'localhost' 'redis' - REDIS['port'] = os.getenv('AE_REDIS_PORT', '6379') # '6379' + REDIS: Dict[str, str] = { + "server": os.getenv('AE_REDIS_SERVER', 'redis'), + "port": os.getenv('AE_REDIS_PORT', '6379') + } + # CORS + ORIGINS_REGEX: str = os.getenv('AE_API_ORIGINS_REGEX', '(https://.*\.oneskyit\.com)|(https://.*\.oneskyit\.com:4443)') + ORIGINS: List[str] = ['https://oneskyit.com'] - # Send SMTP Email - SMTP = {} - # server - # port - # username - # password - - - # Server Hosted File Paths - FILES_PATH = {} - # hosted_files_root - # hosted_tmp_root - - - # CORS Origins - ORIGINS_REGEX = os.getenv('AE_API_ORIGINS_REGEX', '(https://.*\.oneskyit\.com)|(https://.*\.oneskyit\.com:4443)|(https://.*\.oneskyit\.com:8443)') # '(https://.*\.oneskyit\.com)|(http://.*\.oneskyit\.com)|(https://.*\.oneskyit\.com:4443)|(http://.*\.oneskyit\.com:8080)|(http://.*\.oneskyit\.com:8181)|(https://.*\.oneskyit\.com:8443)|(http://.*\.oneskyit\.local)|(http://.*\.oneskyit\.local:5000)|(http://.*.localhost)|(http://.*.localhost:5000)|(http://.*.localhost:8181)' - # A reasonable, but fairly open example regular expression for the CORS origins: - # '(https://.*\.oneskyit\.com)|(http://.*\.oneskyit\.com)|(http://.*\.oneskyit\.com:8181)|(https://.*\.oneskyit\.com:8443)|(http://.*\.oneskyit\.local)|(http://.*\.oneskyit\.local:5000)|(http://.*.localhost)|(http://.*.localhost:5000)|(http://.*.localhost:8181)' - - ORIGINS = [ - 'https://oneskyit.com', - # 'http://app-local.oneskyit.com', - # 'http://192.168.32.20:3000', - # 'http://192.168.32.20:8080', - - # 'http://localhost', - # 'http://localhost:3000', - # 'http://localhost:5000', - # 'http://localhost:7800', - # 'http://localhost:8080', - # 'http://localhost:8888', - - # 'http://fastapi.localhost', - - # 'http://svelte.oneskyit.local:5555', - - # 'http://connect.localhost:5000', # Using localhost - - # 'http://dev-svelte.oneskyit.local:5555', - - # 'http://lci.internal:5000', # Using internal; just in case guess before LCI - # 'http://lci.oneskyit.internal:5000', # Using internal; just in case guess before LCI - # 'http://lci.oneskyit.internal', # Using internal; just in case guess before LCI - ] - - -settings = Settings() +settings = Settings() \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index bff8ba5..04ef0a0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,9 +30,6 @@ services: - ./conf/certs/oneskyit.com_privkey.pem:/etc/certs/privkey.pem - ./conf/certs/ssl-dhparams.pem:/etc/certs/ssl-dhparams.pem - ./logs/web:/logs - networks: - - ae_public - - ae_private depends_on: - ae_api - aether_app_gunicorn @@ -47,8 +44,6 @@ services: container_name: ${CONTAINER_REDIS} image: redis command: redis-server --save "" --loglevel warning - networks: - - ae_private logging: driver: "json-file" options: @@ -76,8 +71,6 @@ services: volumes: - ./srv/mariadb:/var/lib/mysql - ./conf/mariadb/server.cnf:/etc/mysql/conf.d/server.cnf - networks: - - ae_private logging: driver: "json-file" options: @@ -93,9 +86,6 @@ services: UPLOAD_LIMIT: 64M ports: - "${AE_PMA_PORT}:80" - networks: - - ae_public - - ae_private depends_on: - mariadb logging: @@ -110,12 +100,6 @@ services: context: ./ dockerfile: aether_fastapi_gunicorn.Dockerfile scale: ${AE_API_REPLICAS} - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:5005/docs"] - interval: 10s - timeout: 5s - retries: 3 - start_period: 10s env_file: - ./.env extra_hosts: @@ -134,8 +118,6 @@ services: - ${HOSTED_FILES_SRC}:/srv/hosted_files - ${HOSTED_TMP_SRC}:/srv/hosted_tmp - ./temp/ae_api:/temp - networks: - - ae_private depends_on: - redis - mariadb @@ -148,6 +130,7 @@ services: max-file: "3" aether_app_gunicorn: + # ... (same as before) ... restart: always container_name: ${CONTAINER_AE_APP} build: @@ -170,9 +153,6 @@ services: - ${HOSTED_FILES_SRC}:/srv/hosted_files - ${HOSTED_TMP_SRC}:/srv/hosted_tmp - ./tmp/ae_app:/tmp - networks: - - ae_public - - ae_private depends_on: - ae_api stdin_open: true @@ -190,8 +170,6 @@ services: - /var/run/docker.sock:/var/run/docker.sock ports: - "8881:8080" - networks: - - ae_public restart: unless-stopped logging: driver: "json-file" @@ -199,9 +177,28 @@ services: max-size: "10m" max-file: "3" + ae_ops: + # ... (same as before) ... + container_name: ae_ops_dev + image: alpine:latest + restart: always + env_file: + - ./.env + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./backups:/backups + - ./scripts:/scripts + - ./logs:/logs + - ./conf/crontab:/etc/crontabs/root + command: sh -c "apk add --no-cache docker-cli bash && crond -f -l 2" + depends_on: + - mariadb + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + networks: - ae_public: - name: ae_dev_public - ae_private: - name: ae_dev_private - internal: true + default: + name: ae_dev_net \ No newline at end of file