kanban-app/backend/app/services/storage/storage_extension.py

123 lines
3.8 KiB
Python

"""Flask extension for MinIO storage client initialization"""
import logging
from flask import Flask
from minio import Minio
from minio.error import S3Error
class StorageExtension:
"""Flask extension for managing MinIO storage client"""
def __init__(self, app: Flask = None):
"""
Initialize StorageExtension
Args:
app: Flask application instance (optional)
"""
self.app = app
self.client = None
self.logger = logging.getLogger(__name__)
if app is not None:
self.init_app(app)
def init_app(self, app: Flask) -> None:
"""
Initialize the extension with Flask app
Args:
app: Flask application instance
"""
# Store extension on app
app.extensions = getattr(app, "extensions", {})
app.extensions["storage"] = self
# Store app reference for later use
self.app = app
# Initialize and validate MinIO client immediately at app startup
self._initialize_and_validate(app)
def _initialize_and_validate(self, app: Flask) -> None:
"""
Initialize MinIO client and validate connection
Args:
app: Flask application instance
"""
try:
# Create MinIO client
self.client = Minio(
app.config["MINIO_ENDPOINT"],
access_key=app.config["MINIO_ACCESS_KEY"],
secret_key=app.config["MINIO_SECRET_KEY"],
secure=app.config["MINIO_USE_SSL"],
region=app.config["MINIO_REGION"],
)
# Validate connection by listing buckets
self.client.list_buckets()
app.logger.info("MinIO client initialized and validated successfully")
# Ensure all required buckets exist
self._ensure_all_buckets_exist(app)
except S3Error as e:
app.logger.error(f"Failed to initialize MinIO client: {e}")
raise RuntimeError(
f"Failed to connect to MinIO at {app.config['MINIO_ENDPOINT']}. "
"Please check your MINIO_ENDPOINT, MINIO_ACCESS_KEY, "
"and MINIO_SECRET_KEY configuration."
) from e
except KeyError as e:
app.logger.error(f"Missing MinIO configuration: {e}")
raise RuntimeError(
f"Missing required MinIO configuration: {e}. "
"Please ensure MINIO_ENDPOINT, MINIO_ACCESS_KEY, "
"MINIO_SECRET_KEY are set."
) from e
def _ensure_all_buckets_exist(self, app: Flask) -> None:
"""
Ensure all required buckets exist
Creates buckets if they don't exist
Args:
app: Flask application instance
"""
buckets = [
app.config["MINIO_IMAGES_BUCKET"],
app.config["MINIO_DOCUMENTS_BUCKET"],
app.config["MINIO_THUMBNAILS_BUCKET"],
]
for bucket_name in buckets:
if self.client.bucket_exists(bucket_name):
app.logger.debug(f"MinIO bucket exists: {bucket_name}")
else:
app.logger.error(f"MinIO bucket does not exists: {bucket_name}")
raise RuntimeError(f"Failed to create MinIO bucket '{bucket_name}'")
def get_client(self) -> Minio:
"""
Get the MinIO client instance
Returns:
Minio: Initialized MinIO client
Raises:
RuntimeError: If client has not been initialized
"""
if self.client is None:
raise RuntimeError(
"MinIO client has not been initialized. "
"Ensure the Flask app context is active "
"and before_first_request has run."
)
return self.client
# Create a singleton instance
storage = StorageExtension()