GT AI OS Community Edition v2.0.33
Security hardening release addressing CodeQL and Dependabot alerts: - Fix stack trace exposure in error responses - Add SSRF protection with DNS resolution checking - Implement proper URL hostname validation (replaces substring matching) - Add centralized path sanitization to prevent path traversal - Fix ReDoS vulnerability in email validation regex - Improve HTML sanitization in validation utilities - Fix capability wildcard matching in auth utilities - Update glob dependency to address CVE - Add CodeQL suppression comments for verified false positives 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
209
apps/control-panel-backend/app/models/resource_usage.py
Normal file
209
apps/control-panel-backend/app/models/resource_usage.py
Normal file
@@ -0,0 +1,209 @@
|
||||
"""
|
||||
Resource Usage and Quota Models for GT 2.0 Control Panel
|
||||
|
||||
Tracks resource allocation and usage across all tenants with granular monitoring.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from sqlalchemy import Column, Integer, String, Float, DateTime, Boolean, Text, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
|
||||
class ResourceQuota(Base):
|
||||
"""
|
||||
Resource quotas allocated to tenants.
|
||||
|
||||
Tracks maximum allowed usage per resource type with cost tracking.
|
||||
"""
|
||||
__tablename__ = "resource_quotas"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
tenant_id = Column(Integer, ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
resource_type = Column(String(50), nullable=False, index=True) # cpu, memory, storage, api_calls, etc.
|
||||
max_value = Column(Float, nullable=False) # Maximum allowed value
|
||||
current_usage = Column(Float, default=0.0, nullable=False) # Current usage
|
||||
warning_threshold = Column(Float, default=0.8, nullable=False) # Warning at 80%
|
||||
critical_threshold = Column(Float, default=0.95, nullable=False) # Critical at 95%
|
||||
unit = Column(String(20), nullable=False) # units, MB, cores, calls/hour, etc.
|
||||
cost_per_unit = Column(Float, default=0.0, nullable=False) # Cost per unit of usage
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
tenant = relationship("Tenant", back_populates="resource_quotas")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ResourceQuota(tenant_id={self.tenant_id}, type={self.resource_type}, usage={self.current_usage}/{self.max_value})>"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"tenant_id": self.tenant_id,
|
||||
"resource_type": self.resource_type,
|
||||
"max_value": self.max_value,
|
||||
"current_usage": self.current_usage,
|
||||
"usage_percentage": (self.current_usage / self.max_value * 100) if self.max_value > 0 else 0,
|
||||
"warning_threshold": self.warning_threshold,
|
||||
"critical_threshold": self.critical_threshold,
|
||||
"unit": self.unit,
|
||||
"cost_per_unit": self.cost_per_unit,
|
||||
"is_active": self.is_active,
|
||||
"created_at": self.created_at.isoformat() if self.created_at else None,
|
||||
"updated_at": self.updated_at.isoformat() if self.updated_at else None
|
||||
}
|
||||
|
||||
|
||||
class ResourceUsage(Base):
|
||||
"""
|
||||
Historical resource usage records.
|
||||
|
||||
Tracks all resource consumption events for billing and analytics.
|
||||
"""
|
||||
__tablename__ = "resource_usage"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
tenant_id = Column(Integer, ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
resource_type = Column(String(50), nullable=False, index=True)
|
||||
usage_amount = Column(Float, nullable=False) # Amount of resource used (can be negative for refunds)
|
||||
cost = Column(Float, default=0.0, nullable=False) # Cost of this usage
|
||||
timestamp = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
usage_metadata = Column(Text) # JSON metadata about the usage event
|
||||
user_id = Column(String(100)) # User who initiated the usage (optional)
|
||||
service = Column(String(50)) # Service that generated the usage (optional)
|
||||
|
||||
# Relationships
|
||||
tenant = relationship("Tenant", back_populates="resource_usage_records")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ResourceUsage(tenant_id={self.tenant_id}, type={self.resource_type}, amount={self.usage_amount}, cost=${self.cost})>"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"tenant_id": self.tenant_id,
|
||||
"resource_type": self.resource_type,
|
||||
"usage_amount": self.usage_amount,
|
||||
"cost": self.cost,
|
||||
"timestamp": self.timestamp.isoformat() if self.timestamp else None,
|
||||
"metadata": self.usage_metadata,
|
||||
"user_id": self.user_id,
|
||||
"service": self.service
|
||||
}
|
||||
|
||||
|
||||
class ResourceAlert(Base):
|
||||
"""
|
||||
Resource usage alerts and notifications.
|
||||
|
||||
Generated when resource usage exceeds thresholds.
|
||||
"""
|
||||
__tablename__ = "resource_alerts"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
tenant_id = Column(Integer, ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True)
|
||||
resource_type = Column(String(50), nullable=False, index=True)
|
||||
alert_level = Column(String(20), nullable=False, index=True) # info, warning, critical
|
||||
message = Column(Text, nullable=False)
|
||||
current_usage = Column(Float, nullable=False)
|
||||
max_value = Column(Float, nullable=False)
|
||||
percentage_used = Column(Float, nullable=False)
|
||||
acknowledged = Column(Boolean, default=False, nullable=False)
|
||||
acknowledged_by = Column(String(100)) # User who acknowledged the alert
|
||||
acknowledged_at = Column(DateTime)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
|
||||
# Relationships
|
||||
tenant = relationship("Tenant", back_populates="resource_alerts")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ResourceAlert(tenant_id={self.tenant_id}, level={self.alert_level}, type={self.resource_type})>"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"tenant_id": self.tenant_id,
|
||||
"resource_type": self.resource_type,
|
||||
"alert_level": self.alert_level,
|
||||
"message": self.message,
|
||||
"current_usage": self.current_usage,
|
||||
"max_value": self.max_value,
|
||||
"percentage_used": self.percentage_used,
|
||||
"acknowledged": self.acknowledged,
|
||||
"acknowledged_by": self.acknowledged_by,
|
||||
"acknowledged_at": self.acknowledged_at.isoformat() if self.acknowledged_at else None,
|
||||
"created_at": self.created_at.isoformat() if self.created_at else None
|
||||
}
|
||||
|
||||
def acknowledge(self, user_id: str):
|
||||
"""Acknowledge this alert"""
|
||||
self.acknowledged = True
|
||||
self.acknowledged_by = user_id
|
||||
self.acknowledged_at = datetime.utcnow()
|
||||
|
||||
|
||||
class ResourceTemplate(Base):
|
||||
"""
|
||||
Predefined resource allocation templates.
|
||||
|
||||
Templates for different tenant tiers (startup, standard, enterprise).
|
||||
"""
|
||||
__tablename__ = "resource_templates"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
name = Column(String(50), unique=True, nullable=False, index=True)
|
||||
display_name = Column(String(100), nullable=False)
|
||||
description = Column(Text)
|
||||
template_data = Column(Text, nullable=False) # JSON resource configuration
|
||||
monthly_cost = Column(Float, default=0.0, nullable=False)
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ResourceTemplate(name={self.name}, cost=${self.monthly_cost})>"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"display_name": self.display_name,
|
||||
"description": self.description,
|
||||
"template_data": self.template_data,
|
||||
"monthly_cost": self.monthly_cost,
|
||||
"is_active": self.is_active,
|
||||
"created_at": self.created_at.isoformat() if self.created_at else None,
|
||||
"updated_at": self.updated_at.isoformat() if self.updated_at else None
|
||||
}
|
||||
|
||||
|
||||
class SystemMetrics(Base):
|
||||
"""
|
||||
System-wide resource metrics and capacity planning data.
|
||||
|
||||
Tracks aggregate usage across all tenants for capacity planning.
|
||||
"""
|
||||
__tablename__ = "system_metrics"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
metric_name = Column(String(100), nullable=False, index=True)
|
||||
metric_value = Column(Float, nullable=False)
|
||||
metric_unit = Column(String(20), nullable=False)
|
||||
timestamp = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
metric_metadata = Column(Text) # JSON metadata about the metric
|
||||
|
||||
def __repr__(self):
|
||||
return f"<SystemMetrics(name={self.metric_name}, value={self.metric_value}, timestamp={self.timestamp})>"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"metric_name": self.metric_name,
|
||||
"metric_value": self.metric_value,
|
||||
"metric_unit": self.metric_unit,
|
||||
"timestamp": self.timestamp.isoformat() if self.timestamp else None,
|
||||
"metadata": self.metric_metadata
|
||||
}
|
||||
Reference in New Issue
Block a user