New alert service

This commit is contained in:
Urtzi Alfaro
2025-12-05 20:07:01 +01:00
parent 1fe3a73549
commit 667e6e0404
393 changed files with 26002 additions and 61033 deletions

View File

@@ -340,27 +340,85 @@ class ArtifactRepository(TrainingBaseRepository):
}
async def verify_artifact_integrity(self, artifact_id: int) -> Dict[str, Any]:
"""Verify artifact file integrity (placeholder for file system checks)"""
"""Verify artifact file integrity with actual file system checks"""
try:
import os
import hashlib
artifact = await self.get_by_id(artifact_id)
if not artifact:
return {"exists": False, "error": "Artifact not found"}
# This is a placeholder - in a real implementation, you would:
# 1. Check if the file exists at artifact.file_path
# 2. Calculate current checksum and compare with stored checksum
# 3. Verify file size matches stored file_size_bytes
return {
# Check if file exists
file_exists = os.path.exists(artifact.file_path)
if not file_exists:
return {
"artifact_id": artifact_id,
"file_path": artifact.file_path,
"exists": False,
"checksum_valid": False,
"size_valid": False,
"storage_location": artifact.storage_location,
"last_verified": datetime.now().isoformat(),
"error": "File does not exist on disk"
}
# Verify file size
actual_size = os.path.getsize(artifact.file_path)
size_valid = True
if artifact.file_size_bytes:
size_valid = (actual_size == artifact.file_size_bytes)
# Verify checksum if stored
checksum_valid = True
actual_checksum = None
if artifact.checksum:
# Calculate checksum of actual file
sha256_hash = hashlib.sha256()
try:
with open(artifact.file_path, "rb") as f:
# Read file in chunks to handle large files
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
actual_checksum = sha256_hash.hexdigest()
checksum_valid = (actual_checksum == artifact.checksum)
except Exception as checksum_error:
logger.error(f"Failed to calculate checksum: {checksum_error}")
checksum_valid = False
actual_checksum = None
# Overall integrity status
integrity_valid = file_exists and size_valid and checksum_valid
result = {
"artifact_id": artifact_id,
"file_path": artifact.file_path,
"exists": True, # Would check actual file existence
"checksum_valid": True, # Would verify actual checksum
"size_valid": True, # Would verify actual file size
"exists": file_exists,
"checksum_valid": checksum_valid,
"size_valid": size_valid,
"integrity_valid": integrity_valid,
"storage_location": artifact.storage_location,
"last_verified": datetime.now().isoformat()
"last_verified": datetime.now().isoformat(),
"details": {
"stored_size_bytes": artifact.file_size_bytes,
"actual_size_bytes": actual_size if file_exists else None,
"stored_checksum": artifact.checksum,
"actual_checksum": actual_checksum
}
}
if not integrity_valid:
issues = []
if not file_exists:
issues.append("file_missing")
if not size_valid:
issues.append("size_mismatch")
if not checksum_valid:
issues.append("checksum_mismatch")
result["issues"] = issues
return result
except Exception as e:
logger.error("Failed to verify artifact integrity",
artifact_id=artifact_id,
@@ -374,55 +432,124 @@ class ArtifactRepository(TrainingBaseRepository):
self,
from_location: str,
to_location: str,
tenant_id: str = None
tenant_id: str = None,
copy_only: bool = False,
verify: bool = True
) -> Dict[str, Any]:
"""Migrate artifacts from one storage location to another (placeholder)"""
"""Migrate artifacts from one storage location to another with actual file operations"""
try:
import os
import shutil
import hashlib
# Get artifacts to migrate
artifacts = await self.get_artifacts_by_storage_location(from_location, tenant_id)
migrated_count = 0
failed_count = 0
# This is a placeholder - in a real implementation, you would:
# 1. Copy files from old location to new location
# 2. Update file paths in database
# 3. Verify successful migration
# 4. Clean up old files
failed_artifacts = []
verified_count = 0
for artifact in artifacts:
try:
# Placeholder migration logic
new_file_path = artifact.file_path.replace(from_location, to_location)
# Determine new file path
new_file_path = artifact.file_path.replace(from_location, to_location, 1)
# Create destination directory if it doesn't exist
dest_dir = os.path.dirname(new_file_path)
os.makedirs(dest_dir, exist_ok=True)
# Check if source file exists
if not os.path.exists(artifact.file_path):
logger.warning(f"Source file not found: {artifact.file_path}")
failed_count += 1
failed_artifacts.append({
"artifact_id": artifact.id,
"file_path": artifact.file_path,
"reason": "source_file_not_found"
})
continue
# Copy or move file
if copy_only:
shutil.copy2(artifact.file_path, new_file_path)
logger.debug(f"Copied file from {artifact.file_path} to {new_file_path}")
else:
shutil.move(artifact.file_path, new_file_path)
logger.debug(f"Moved file from {artifact.file_path} to {new_file_path}")
# Verify file was copied/moved successfully
if verify and os.path.exists(new_file_path):
# Verify file size
new_size = os.path.getsize(new_file_path)
if artifact.file_size_bytes and new_size != artifact.file_size_bytes:
logger.warning(f"File size mismatch after migration: {new_file_path}")
failed_count += 1
failed_artifacts.append({
"artifact_id": artifact.id,
"file_path": new_file_path,
"reason": "size_mismatch_after_migration"
})
continue
# Verify checksum if available
if artifact.checksum:
sha256_hash = hashlib.sha256()
with open(new_file_path, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
new_checksum = sha256_hash.hexdigest()
if new_checksum != artifact.checksum:
logger.warning(f"Checksum mismatch after migration: {new_file_path}")
failed_count += 1
failed_artifacts.append({
"artifact_id": artifact.id,
"file_path": new_file_path,
"reason": "checksum_mismatch_after_migration"
})
continue
verified_count += 1
# Update database with new location
await self.update(artifact.id, {
"storage_location": to_location,
"file_path": new_file_path
})
migrated_count += 1
except Exception as migration_error:
logger.error("Failed to migrate artifact",
artifact_id=artifact.id,
error=str(migration_error))
failed_count += 1
failed_artifacts.append({
"artifact_id": artifact.id,
"file_path": artifact.file_path,
"reason": str(migration_error)
})
logger.info("Artifact migration completed",
from_location=from_location,
to_location=to_location,
migrated_count=migrated_count,
failed_count=failed_count)
failed_count=failed_count,
verified_count=verified_count)
return {
"from_location": from_location,
"to_location": to_location,
"total_artifacts": len(artifacts),
"migrated_count": migrated_count,
"failed_count": failed_count,
"success_rate": round((migrated_count / len(artifacts)) * 100, 2) if artifacts else 100
"verified_count": verified_count if verify else None,
"success_rate": round((migrated_count / len(artifacts)) * 100, 2) if artifacts else 100,
"copy_only": copy_only,
"failed_artifacts": failed_artifacts if failed_artifacts else None
}
except Exception as e:
logger.error("Failed to migrate artifacts",
from_location=from_location,