QTZPOC-20
QTZPOC-20: Implement .sientia model bundle import workflow Introduces a new Temporal workflow and activities to import .sientia model bundles. This enables: - Secure decryption and validation of bundles through a seven-gate process. - Provisioning imported models in MLflow and updating the MongoDB model listing. - Comprehensive status tracking in the public.experiment_run table with new IMPORT_SUCCESS/IMPORT_ERROR states. - Dedicated metrics, robust error handling, and configurable settings. - Includes updated e2e database fixtures and extensive unit/integration tests for bundle format, reader, and overall workflow.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
from os import getenv
|
||||
import tempfile
|
||||
from os import getenv, path
|
||||
from typing import Any
|
||||
|
||||
|
||||
@@ -90,3 +91,72 @@ def build_minio_config() -> dict[str, Any]:
|
||||
'retention_hours': int(getenv('MINIO_RETENTION_HOURS', '24')),
|
||||
'secure': getenv('MINIO_SECURE', 'false') == 'true',
|
||||
}
|
||||
|
||||
|
||||
def build_import_config() -> dict[str, Any]:
|
||||
"""
|
||||
Build the `.sientia` model-import configuration from environment variables.
|
||||
|
||||
The password key is read as the raw base64 string and **not** validated here: the worker must
|
||||
start whether or not `IMPORT_MODEL_ENABLED` is set, and a missing or malformed key is an import
|
||||
failure at the decryption step (`laborious.utils.import_password.load_envelope_key`), not a
|
||||
boot failure.
|
||||
|
||||
Environment Variables:
|
||||
IMPORT_PASSWORD_KEY: base64 of the 32-byte AES-256-GCM key that wraps bundle passwords
|
||||
IMPORT_BUNDLE_BUCKET: bucket holding the uploaded bundles (default: sientia)
|
||||
IMPORT_BUNDLE_PREFIX: key prefix the uploads must sit under (default: imported_models/)
|
||||
IMPORT_WORK_DIR: worker scratch directory (default: <tempdir>/sientia-import)
|
||||
IMPORT_MAX_OBJECT_BYTES: gate 1 object size ceiling (default: 1 GiB)
|
||||
IMPORT_MAX_ARCHIVE_ENTRIES: gate 4 entry count ceiling (default: 5000)
|
||||
IMPORT_MAX_UNCOMPRESSED_BYTES: gate 4 uncompressed size ceiling (default: 4 GiB)
|
||||
IMPORT_MAX_COMPRESSION_RATIO: gate 4 compression ratio ceiling (default: 200)
|
||||
IMPORT_MODELS_COLLECTION: MongoDB collection holding the model listing (default: models)
|
||||
IMPORT_BUNDLE_RETENTION_DAYS: lifecycle expiry for the uploaded bundle (default: 7)
|
||||
|
||||
Returns:
|
||||
dict: import configuration dictionary
|
||||
"""
|
||||
prefix = getenv('IMPORT_BUNDLE_PREFIX', 'imported_models/')
|
||||
return {
|
||||
'password_key': getenv('IMPORT_PASSWORD_KEY'),
|
||||
'bucket': getenv('IMPORT_BUNDLE_BUCKET', 'sientia'),
|
||||
'prefix': prefix if prefix.endswith('/') else f'{prefix}/',
|
||||
'work_dir': getenv('IMPORT_WORK_DIR', path.join(tempfile.gettempdir(), 'sientia-import')),
|
||||
'max_object_bytes': int(getenv('IMPORT_MAX_OBJECT_BYTES', str(1024 * 1024 * 1024))),
|
||||
'max_entries': int(getenv('IMPORT_MAX_ARCHIVE_ENTRIES', '5000')),
|
||||
'max_uncompressed_bytes': int(
|
||||
getenv('IMPORT_MAX_UNCOMPRESSED_BYTES', str(4 * 1024 * 1024 * 1024))
|
||||
),
|
||||
'max_compression_ratio': float(getenv('IMPORT_MAX_COMPRESSION_RATIO', '200')),
|
||||
'models_collection': getenv('IMPORT_MODELS_COLLECTION', 'models'),
|
||||
'retention_days': int(getenv('IMPORT_BUNDLE_RETENTION_DAYS', '7')),
|
||||
}
|
||||
|
||||
|
||||
def build_import_status_config() -> dict[str, Any]:
|
||||
"""
|
||||
Build the connection to the import log database — a **second** Postgres connection.
|
||||
|
||||
The import log is `public.experiment_run` in the database owned by the Spring Boot BFF
|
||||
(`sientia-core-mlops-bff`), not the `sientia` database Laborious itself uses. The table and
|
||||
schema are constants of the code, never inputs; only the connection is configuration.
|
||||
|
||||
Environment Variables:
|
||||
IMPORT_STATUS_DB_HOST: host (default: localhost)
|
||||
IMPORT_STATUS_DB_PORT: port (default: 5432)
|
||||
IMPORT_STATUS_DB_NAME: database (default: sientia-core-mlops-bff)
|
||||
IMPORT_STATUS_DB_USER: user (default: mlops_bff_user)
|
||||
IMPORT_STATUS_DB_PASSWORD: password (default: empty)
|
||||
|
||||
Returns:
|
||||
dict: import status database configuration dictionary
|
||||
"""
|
||||
return {
|
||||
'host': getenv('IMPORT_STATUS_DB_HOST', 'localhost'),
|
||||
'port': int(getenv('IMPORT_STATUS_DB_PORT', '5432')),
|
||||
'dbname': getenv('IMPORT_STATUS_DB_NAME', 'sientia-core-mlops-bff'),
|
||||
'user': getenv('IMPORT_STATUS_DB_USER', 'mlops_bff_user'),
|
||||
'password': getenv('IMPORT_STATUS_DB_PASSWORD', ''),
|
||||
'schema': 'public',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user