first commit
This commit is contained in:
15
backend/app/models/__init__.py
Normal file
15
backend/app/models/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from app.models.user import User
|
||||
from app.models.gpu_cluster import GPUCluster
|
||||
from app.models.task import CollectionTask
|
||||
from app.models.datasource import DataSource
|
||||
from app.models.alert import Alert, AlertSeverity, AlertStatus
|
||||
|
||||
__all__ = [
|
||||
"User",
|
||||
"GPUCluster",
|
||||
"CollectionTask",
|
||||
"DataSource",
|
||||
"Alert",
|
||||
"AlertSeverity",
|
||||
"AlertStatus",
|
||||
]
|
||||
BIN
backend/app/models/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
backend/app/models/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
backend/app/models/__pycache__/alert.cpython-311.pyc
Normal file
BIN
backend/app/models/__pycache__/alert.cpython-311.pyc
Normal file
Binary file not shown.
BIN
backend/app/models/__pycache__/collected_data.cpython-311.pyc
Normal file
BIN
backend/app/models/__pycache__/collected_data.cpython-311.pyc
Normal file
Binary file not shown.
BIN
backend/app/models/__pycache__/datasource.cpython-311.pyc
Normal file
BIN
backend/app/models/__pycache__/datasource.cpython-311.pyc
Normal file
Binary file not shown.
BIN
backend/app/models/__pycache__/datasource_config.cpython-311.pyc
Normal file
BIN
backend/app/models/__pycache__/datasource_config.cpython-311.pyc
Normal file
Binary file not shown.
BIN
backend/app/models/__pycache__/gpu_cluster.cpython-311.pyc
Normal file
BIN
backend/app/models/__pycache__/gpu_cluster.cpython-311.pyc
Normal file
Binary file not shown.
BIN
backend/app/models/__pycache__/task.cpython-311.pyc
Normal file
BIN
backend/app/models/__pycache__/task.cpython-311.pyc
Normal file
Binary file not shown.
BIN
backend/app/models/__pycache__/user.cpython-311.pyc
Normal file
BIN
backend/app/models/__pycache__/user.cpython-311.pyc
Normal file
Binary file not shown.
57
backend/app/models/alert.py
Normal file
57
backend/app/models/alert.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Text, ForeignKey, Enum as SQLEnum
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from app.db.session import Base
|
||||
|
||||
|
||||
class AlertSeverity(str, Enum):
|
||||
CRITICAL = "critical"
|
||||
WARNING = "warning"
|
||||
INFO = "info"
|
||||
|
||||
|
||||
class AlertStatus(str, Enum):
|
||||
ACTIVE = "active"
|
||||
ACKNOWLEDGED = "acknowledged"
|
||||
RESOLVED = "resolved"
|
||||
|
||||
|
||||
class Alert(Base):
|
||||
__tablename__ = "alerts"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
severity = Column(SQLEnum(AlertSeverity), default=AlertSeverity.WARNING)
|
||||
status = Column(SQLEnum(AlertStatus), default=AlertStatus.ACTIVE)
|
||||
datasource_id = Column(Integer, nullable=True, index=True)
|
||||
datasource_name = Column(String(255), nullable=True)
|
||||
message = Column(Text)
|
||||
alert_metadata = Column(Text, nullable=True)
|
||||
acknowledged_by = Column(Integer, nullable=True)
|
||||
resolved_by = Column(Integer, nullable=True)
|
||||
resolution_notes = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
acknowledged_at = Column(DateTime, nullable=True)
|
||||
resolved_at = Column(DateTime, nullable=True)
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"severity": self.severity.value if self.severity else None,
|
||||
"status": self.status.value if self.status else None,
|
||||
"datasource_id": self.datasource_id,
|
||||
"datasource_name": self.datasource_name,
|
||||
"message": self.message,
|
||||
"alert_metadata": self.alert_metadata,
|
||||
"acknowledged_by": self.acknowledged_by,
|
||||
"resolved_by": self.resolved_by,
|
||||
"resolution_notes": self.resolution_notes,
|
||||
"created_at": self.created_at.isoformat() if self.created_at else None,
|
||||
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
||||
"acknowledged_at": self.acknowledged_at.isoformat() if self.acknowledged_at else None,
|
||||
"resolved_at": self.resolved_at.isoformat() if self.resolved_at else None,
|
||||
}
|
||||
80
backend/app/models/collected_data.py
Normal file
80
backend/app/models/collected_data.py
Normal file
@@ -0,0 +1,80 @@
|
||||
"""Collected Data model for storing data from all collectors"""
|
||||
|
||||
from sqlalchemy import Column, DateTime, Integer, String, Text, JSON, Index
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from app.db.session import Base
|
||||
|
||||
|
||||
class CollectedData(Base):
|
||||
"""Generic model for storing collected data from all sources"""
|
||||
|
||||
__tablename__ = "collected_data"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
source = Column(String(100), nullable=False, index=True) # e.g., "top500", "huggingface_models"
|
||||
source_id = Column(String(100), index=True) # Original ID from source, e.g., "rank_1"
|
||||
data_type = Column(
|
||||
String(50), nullable=False, index=True
|
||||
) # e.g., "supercomputer", "model", "dataset"
|
||||
|
||||
# Core data fields
|
||||
name = Column(String(500))
|
||||
title = Column(String(500))
|
||||
description = Column(Text)
|
||||
|
||||
# Location data (for geo visualization)
|
||||
country = Column(String(100))
|
||||
city = Column(String(100))
|
||||
latitude = Column(String(50))
|
||||
longitude = Column(String(50))
|
||||
|
||||
# Performance metrics
|
||||
value = Column(String(100)) # Generic value field (Rmax, Rpeak, etc.)
|
||||
unit = Column(String(20))
|
||||
|
||||
# Additional metadata as JSON
|
||||
extra_data = Column(
|
||||
"metadata", JSON, default={}
|
||||
) # Using 'extra_data' as attribute name but 'metadata' as column name
|
||||
|
||||
# Timestamps
|
||||
collected_at = Column(DateTime(timezone=True), server_default=func.now(), index=True)
|
||||
reference_date = Column(DateTime(timezone=True)) # Data reference date (e.g., TOP500 list date)
|
||||
|
||||
# Status
|
||||
is_valid = Column(Integer, default=1) # 1=valid, 0=invalid
|
||||
|
||||
# Indexes for common queries
|
||||
__table_args__ = (
|
||||
Index("idx_collected_data_source_collected", "source", "collected_at"),
|
||||
Index("idx_collected_data_source_type", "source", "data_type"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<CollectedData {self.id}: {self.source}/{self.data_type}>"
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Convert to dictionary"""
|
||||
return {
|
||||
"id": self.id,
|
||||
"source": self.source,
|
||||
"source_id": self.source_id,
|
||||
"data_type": self.data_type,
|
||||
"name": self.name,
|
||||
"title": self.title,
|
||||
"description": self.description,
|
||||
"country": self.country,
|
||||
"city": self.city,
|
||||
"latitude": self.latitude,
|
||||
"longitude": self.longitude,
|
||||
"value": self.value,
|
||||
"unit": self.unit,
|
||||
"metadata": self.extra_data,
|
||||
"collected_at": self.collected_at.isoformat()
|
||||
if self.collected_at is not None
|
||||
else None,
|
||||
"reference_date": self.reference_date.isoformat()
|
||||
if self.reference_date is not None
|
||||
else None,
|
||||
}
|
||||
28
backend/app/models/datasource.py
Normal file
28
backend/app/models/datasource.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""Data Source model"""
|
||||
|
||||
from sqlalchemy import Boolean, Column, DateTime, Integer, String, Text
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from app.db.session import Base
|
||||
|
||||
|
||||
class DataSource(Base):
|
||||
__tablename__ = "data_sources"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
name = Column(String(100), nullable=False)
|
||||
source = Column(String(100), nullable=False)
|
||||
module = Column(String(10), nullable=False, index=True) # L1, L2, L3, L4
|
||||
priority = Column(String(10), default="P1") # P0, P1, P2
|
||||
frequency_minutes = Column(Integer, default=60)
|
||||
collector_class = Column(String(100), nullable=False)
|
||||
config = Column(Text, default="{}") # JSON config
|
||||
is_active = Column(Boolean, default=True, index=True)
|
||||
last_run_at = Column(DateTime(timezone=True))
|
||||
last_status = Column(String(20))
|
||||
next_run_at = Column(DateTime(timezone=True))
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
def __repr__(self):
|
||||
return f"<DataSource {self.id}: {self.name}>"
|
||||
26
backend/app/models/datasource_config.py
Normal file
26
backend/app/models/datasource_config.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""User-defined Data Source Configuration model"""
|
||||
|
||||
from sqlalchemy import Boolean, Column, DateTime, Integer, String, Text, JSON
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from app.db.session import Base
|
||||
|
||||
|
||||
class DataSourceConfig(Base):
|
||||
__tablename__ = "datasource_configs"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
name = Column(String(100), nullable=False)
|
||||
description = Column(Text)
|
||||
source_type = Column(String(50), nullable=False) # http, api, database, etc.
|
||||
endpoint = Column(String(500))
|
||||
auth_type = Column(String(20), default="none") # none, bearer, api_key, basic
|
||||
auth_config = Column(JSON, default={}) # Encrypted credentials
|
||||
headers = Column(JSON, default={})
|
||||
config = Column(JSON, default={}) # Additional config like timeout, retry, etc.
|
||||
is_active = Column(Boolean, default=True)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
def __repr__(self):
|
||||
return f"<DataSourceConfig {self.id}: {self.name}>"
|
||||
29
backend/app/models/gpu_cluster.py
Normal file
29
backend/app/models/gpu_cluster.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""GPU Cluster model for L1 data"""
|
||||
|
||||
from sqlalchemy import Column, DateTime, Float, Integer, String, Text
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from app.db.session import Base
|
||||
|
||||
|
||||
class GPUCluster(Base):
|
||||
__tablename__ = "gpu_clusters"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
time = Column(DateTime(timezone=True), nullable=False)
|
||||
cluster_id = Column(String(100), nullable=False, index=True)
|
||||
name = Column(String(200), nullable=False)
|
||||
country = Column(String(100))
|
||||
city = Column(String(100))
|
||||
latitude = Column(Float)
|
||||
longitude = Column(Float)
|
||||
organization = Column(String(200))
|
||||
gpu_count = Column(Integer)
|
||||
gpu_type = Column(String(100))
|
||||
total_flops = Column(Float)
|
||||
rank = Column(Integer)
|
||||
source = Column(String(50), nullable=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
def __repr__(self):
|
||||
return f"<GPUCluster {self.cluster_id}: {self.name}>"
|
||||
22
backend/app/models/task.py
Normal file
22
backend/app/models/task.py
Normal file
@@ -0,0 +1,22 @@
|
||||
"""Collection Task model"""
|
||||
|
||||
from sqlalchemy import Column, DateTime, Integer, String, Text
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from app.db.session import Base
|
||||
|
||||
|
||||
class CollectionTask(Base):
|
||||
__tablename__ = "collection_tasks"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
datasource_id = Column(Integer, nullable=False, index=True)
|
||||
status = Column(String(20), nullable=False) # pending, running, success, failed, cancelled
|
||||
started_at = Column(DateTime(timezone=True))
|
||||
completed_at = Column(DateTime(timezone=True))
|
||||
records_processed = Column(Integer, default=0)
|
||||
error_message = Column(Text)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
def __repr__(self):
|
||||
return f"<CollectionTask {self.id}: {self.status}>"
|
||||
25
backend/app/models/user.py
Normal file
25
backend/app/models/user.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from sqlalchemy import Boolean, Column, Integer, String, DateTime
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from app.db.session import Base
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
username = Column(String(50), unique=True, index=True, nullable=False)
|
||||
email = Column(String(255), unique=True, index=True, nullable=False)
|
||||
password_hash = Column(String(255), nullable=False)
|
||||
role = Column(String(20), default="viewer")
|
||||
is_active = Column(Boolean, default=True)
|
||||
last_login_at = Column(DateTime(timezone=True))
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
def set_password(self, password: str):
|
||||
from app.core.security import get_password_hash
|
||||
|
||||
self.password_hash = get_password_hash(password)
|
||||
Reference in New Issue
Block a user