fix: auto-fix code issues (cron)
- 修复重复导入/字段 - 修复异常处理 - 修复PEP8格式问题 - 添加类型注解 - 修复缺失的urllib.parse导入
This commit is contained in:
@@ -29,6 +29,7 @@ import httpx
|
||||
# Database path
|
||||
DB_PATH = os.path.join(os.path.dirname(__file__), "insightflow.db")
|
||||
|
||||
|
||||
class AlertSeverity(StrEnum):
|
||||
"""告警严重级别 P0-P3"""
|
||||
|
||||
@@ -37,6 +38,7 @@ class AlertSeverity(StrEnum):
|
||||
P2 = "p2" # 一般 - 部分功能受影响,需要4小时内处理
|
||||
P3 = "p3" # 轻微 - 非核心功能问题,24小时内处理
|
||||
|
||||
|
||||
class AlertStatus(StrEnum):
|
||||
"""告警状态"""
|
||||
|
||||
@@ -45,6 +47,7 @@ class AlertStatus(StrEnum):
|
||||
ACKNOWLEDGED = "acknowledged" # 已确认
|
||||
SUPPRESSED = "suppressed" # 已抑制
|
||||
|
||||
|
||||
class AlertChannelType(StrEnum):
|
||||
"""告警渠道类型"""
|
||||
|
||||
@@ -57,6 +60,7 @@ class AlertChannelType(StrEnum):
|
||||
SMS = "sms"
|
||||
WEBHOOK = "webhook"
|
||||
|
||||
|
||||
class AlertRuleType(StrEnum):
|
||||
"""告警规则类型"""
|
||||
|
||||
@@ -65,6 +69,7 @@ class AlertRuleType(StrEnum):
|
||||
PREDICTIVE = "predictive" # 预测性告警
|
||||
COMPOSITE = "composite" # 复合告警
|
||||
|
||||
|
||||
class ResourceType(StrEnum):
|
||||
"""资源类型"""
|
||||
|
||||
@@ -77,6 +82,7 @@ class ResourceType(StrEnum):
|
||||
CACHE = "cache"
|
||||
QUEUE = "queue"
|
||||
|
||||
|
||||
class ScalingAction(StrEnum):
|
||||
"""扩缩容动作"""
|
||||
|
||||
@@ -84,6 +90,7 @@ class ScalingAction(StrEnum):
|
||||
SCALE_DOWN = "scale_down" # 缩容
|
||||
MAINTAIN = "maintain" # 保持
|
||||
|
||||
|
||||
class HealthStatus(StrEnum):
|
||||
"""健康状态"""
|
||||
|
||||
@@ -92,6 +99,7 @@ class HealthStatus(StrEnum):
|
||||
UNHEALTHY = "unhealthy"
|
||||
UNKNOWN = "unknown"
|
||||
|
||||
|
||||
class BackupStatus(StrEnum):
|
||||
"""备份状态"""
|
||||
|
||||
@@ -101,6 +109,7 @@ class BackupStatus(StrEnum):
|
||||
FAILED = "failed"
|
||||
VERIFIED = "verified"
|
||||
|
||||
|
||||
@dataclass
|
||||
class AlertRule:
|
||||
"""告警规则"""
|
||||
@@ -124,6 +133,7 @@ class AlertRule:
|
||||
updated_at: str
|
||||
created_by: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class AlertChannel:
|
||||
"""告警渠道配置"""
|
||||
@@ -141,6 +151,7 @@ class AlertChannel:
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class Alert:
|
||||
"""告警实例"""
|
||||
@@ -164,6 +175,7 @@ class Alert:
|
||||
notification_sent: dict[str, bool] # 渠道发送状态
|
||||
suppression_count: int # 抑制计数
|
||||
|
||||
|
||||
@dataclass
|
||||
class AlertSuppressionRule:
|
||||
"""告警抑制规则"""
|
||||
@@ -177,6 +189,7 @@ class AlertSuppressionRule:
|
||||
created_at: str
|
||||
expires_at: str | None
|
||||
|
||||
|
||||
@dataclass
|
||||
class AlertGroup:
|
||||
"""告警聚合组"""
|
||||
@@ -188,6 +201,7 @@ class AlertGroup:
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ResourceMetric:
|
||||
"""资源指标"""
|
||||
@@ -202,6 +216,7 @@ class ResourceMetric:
|
||||
timestamp: str
|
||||
metadata: dict
|
||||
|
||||
|
||||
@dataclass
|
||||
class CapacityPlan:
|
||||
"""容量规划"""
|
||||
@@ -217,6 +232,7 @@ class CapacityPlan:
|
||||
estimated_cost: float
|
||||
created_at: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class AutoScalingPolicy:
|
||||
"""自动扩缩容策略"""
|
||||
@@ -237,6 +253,7 @@ class AutoScalingPolicy:
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScalingEvent:
|
||||
"""扩缩容事件"""
|
||||
@@ -254,6 +271,7 @@ class ScalingEvent:
|
||||
completed_at: str | None
|
||||
error_message: str | None
|
||||
|
||||
|
||||
@dataclass
|
||||
class HealthCheck:
|
||||
"""健康检查配置"""
|
||||
@@ -274,6 +292,7 @@ class HealthCheck:
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class HealthCheckResult:
|
||||
"""健康检查结果"""
|
||||
@@ -287,6 +306,7 @@ class HealthCheckResult:
|
||||
details: dict
|
||||
checked_at: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class FailoverConfig:
|
||||
"""故障转移配置"""
|
||||
@@ -304,6 +324,7 @@ class FailoverConfig:
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class FailoverEvent:
|
||||
"""故障转移事件"""
|
||||
@@ -319,6 +340,7 @@ class FailoverEvent:
|
||||
completed_at: str | None
|
||||
rolled_back_at: str | None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BackupJob:
|
||||
"""备份任务"""
|
||||
@@ -338,6 +360,7 @@ class BackupJob:
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class BackupRecord:
|
||||
"""备份记录"""
|
||||
@@ -354,6 +377,7 @@ class BackupRecord:
|
||||
error_message: str | None
|
||||
storage_path: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class CostReport:
|
||||
"""成本报告"""
|
||||
@@ -368,6 +392,7 @@ class CostReport:
|
||||
anomalies: list[dict] # 异常检测
|
||||
created_at: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ResourceUtilization:
|
||||
"""资源利用率"""
|
||||
@@ -383,6 +408,7 @@ class ResourceUtilization:
|
||||
report_date: str
|
||||
recommendations: list[str]
|
||||
|
||||
|
||||
@dataclass
|
||||
class IdleResource:
|
||||
"""闲置资源"""
|
||||
@@ -399,6 +425,7 @@ class IdleResource:
|
||||
recommendation: str
|
||||
detected_at: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class CostOptimizationSuggestion:
|
||||
"""成本优化建议"""
|
||||
@@ -418,6 +445,7 @@ class CostOptimizationSuggestion:
|
||||
created_at: str
|
||||
applied_at: str | None
|
||||
|
||||
|
||||
class OpsManager:
|
||||
"""运维与监控管理主类"""
|
||||
|
||||
@@ -577,7 +605,10 @@ class OpsManager:
|
||||
|
||||
with self._get_db() as conn:
|
||||
set_clause = ", ".join([f"{k} = ?" for k in updates.keys()])
|
||||
conn.execute(f"UPDATE alert_rules SET {set_clause} WHERE id = ?", list(updates.values()) + [rule_id])
|
||||
conn.execute(
|
||||
f"UPDATE alert_rules SET {set_clause} WHERE id = ?",
|
||||
list(updates.values()) + [rule_id],
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
return self.get_alert_rule(rule_id)
|
||||
@@ -592,7 +623,12 @@ class OpsManager:
|
||||
# ==================== 告警渠道管理 ====================
|
||||
|
||||
def create_alert_channel(
|
||||
self, tenant_id: str, name: str, channel_type: AlertChannelType, config: dict, severity_filter: list[str] = None
|
||||
self,
|
||||
tenant_id: str,
|
||||
name: str,
|
||||
channel_type: AlertChannelType,
|
||||
config: dict,
|
||||
severity_filter: list[str] = None,
|
||||
) -> AlertChannel:
|
||||
"""创建告警渠道"""
|
||||
channel_id = f"ac_{uuid.uuid4().hex[:16]}"
|
||||
@@ -643,7 +679,9 @@ class OpsManager:
|
||||
def get_alert_channel(self, channel_id: str) -> AlertChannel | None:
|
||||
"""获取告警渠道"""
|
||||
with self._get_db() as conn:
|
||||
row = conn.execute("SELECT * FROM alert_channels WHERE id = ?", (channel_id,)).fetchone()
|
||||
row = conn.execute(
|
||||
"SELECT * FROM alert_channels WHERE id = ?", (channel_id,)
|
||||
).fetchone()
|
||||
|
||||
if row:
|
||||
return self._row_to_alert_channel(row)
|
||||
@@ -653,7 +691,8 @@ class OpsManager:
|
||||
"""列出租户的所有告警渠道"""
|
||||
with self._get_db() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM alert_channels WHERE tenant_id = ? ORDER BY created_at DESC", (tenant_id,)
|
||||
"SELECT * FROM alert_channels WHERE tenant_id = ? ORDER BY created_at DESC",
|
||||
(tenant_id,),
|
||||
).fetchall()
|
||||
return [self._row_to_alert_channel(row) for row in rows]
|
||||
|
||||
@@ -779,7 +818,9 @@ class OpsManager:
|
||||
|
||||
for rule in rules:
|
||||
# 获取相关指标
|
||||
metrics = self.get_recent_metrics(tenant_id, rule.metric, seconds=rule.duration + rule.evaluation_interval)
|
||||
metrics = self.get_recent_metrics(
|
||||
tenant_id, rule.metric, seconds=rule.duration + rule.evaluation_interval
|
||||
)
|
||||
|
||||
# 评估规则
|
||||
evaluator = self._alert_evaluators.get(rule.rule_type.value)
|
||||
@@ -921,7 +962,10 @@ class OpsManager:
|
||||
"card": {
|
||||
"config": {"wide_screen_mode": True},
|
||||
"header": {
|
||||
"title": {"tag": "plain_text", "content": f"🚨 [{alert.severity.value.upper()}] {alert.title}"},
|
||||
"title": {
|
||||
"tag": "plain_text",
|
||||
"content": f"🚨 [{alert.severity.value.upper()}] {alert.title}",
|
||||
},
|
||||
"template": severity_colors.get(alert.severity.value, "blue"),
|
||||
},
|
||||
"elements": [
|
||||
@@ -932,7 +976,10 @@ class OpsManager:
|
||||
"content": f"**描述:** {alert.description}\n\n**指标:** {alert.metric}\n**当前值:** {alert.value}\n**阈值:** {alert.threshold}",
|
||||
},
|
||||
},
|
||||
{"tag": "div", "text": {"tag": "lark_md", "content": f"**时间:** {alert.started_at}"}},
|
||||
{
|
||||
"tag": "div",
|
||||
"text": {"tag": "lark_md", "content": f"**时间:** {alert.started_at}"},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -999,7 +1046,10 @@ class OpsManager:
|
||||
"blocks": [
|
||||
{
|
||||
"type": "header",
|
||||
"text": {"type": "plain_text", "text": f"{emoji} [{alert.severity.value.upper()}] {alert.title}"},
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": f"{emoji} [{alert.severity.value.upper()}] {alert.title}",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
@@ -1010,7 +1060,10 @@ class OpsManager:
|
||||
{"type": "mrkdwn", "text": f"*阈值:*\n{alert.threshold}"},
|
||||
],
|
||||
},
|
||||
{"type": "context", "elements": [{"type": "mrkdwn", "text": f"触发时间: {alert.started_at}"}]},
|
||||
{
|
||||
"type": "context",
|
||||
"elements": [{"type": "mrkdwn", "text": f"触发时间: {alert.started_at}"}],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1070,7 +1123,9 @@ class OpsManager:
|
||||
}
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post("https://events.pagerduty.com/v2/enqueue", json=message, timeout=30.0)
|
||||
response = await client.post(
|
||||
"https://events.pagerduty.com/v2/enqueue", json=message, timeout=30.0
|
||||
)
|
||||
success = response.status_code == 202
|
||||
self._update_channel_stats(channel.id, success)
|
||||
return success
|
||||
@@ -1095,7 +1150,11 @@ class OpsManager:
|
||||
"description": alert.description,
|
||||
"priority": priority_map.get(alert.severity.value, "P3"),
|
||||
"alias": alert.id,
|
||||
"details": {"metric": alert.metric, "value": str(alert.value), "threshold": str(alert.threshold)},
|
||||
"details": {
|
||||
"metric": alert.metric,
|
||||
"value": str(alert.value),
|
||||
"threshold": str(alert.threshold),
|
||||
},
|
||||
}
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
@@ -1234,17 +1293,22 @@ class OpsManager:
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
def _update_alert_notification_status(self, alert_id: str, channel_id: str, success: bool) -> None:
|
||||
def _update_alert_notification_status(
|
||||
self, alert_id: str, channel_id: str, success: bool
|
||||
) -> None:
|
||||
"""更新告警通知状态"""
|
||||
with self._get_db() as conn:
|
||||
row = conn.execute("SELECT notification_sent FROM alerts WHERE id = ?", (alert_id,)).fetchone()
|
||||
row = conn.execute(
|
||||
"SELECT notification_sent FROM alerts WHERE id = ?", (alert_id,)
|
||||
).fetchone()
|
||||
|
||||
if row:
|
||||
notification_sent = json.loads(row["notification_sent"])
|
||||
notification_sent[channel_id] = success
|
||||
|
||||
conn.execute(
|
||||
"UPDATE alerts SET notification_sent = ? WHERE id = ?", (json.dumps(notification_sent), alert_id)
|
||||
"UPDATE alerts SET notification_sent = ? WHERE id = ?",
|
||||
(json.dumps(notification_sent), alert_id),
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
@@ -1409,7 +1473,9 @@ class OpsManager:
|
||||
|
||||
return metric
|
||||
|
||||
def get_recent_metrics(self, tenant_id: str, metric_name: str, seconds: int = 3600) -> list[ResourceMetric]:
|
||||
def get_recent_metrics(
|
||||
self, tenant_id: str, metric_name: str, seconds: int = 3600
|
||||
) -> list[ResourceMetric]:
|
||||
"""获取最近的指标数据"""
|
||||
cutoff_time = (datetime.now() - timedelta(seconds=seconds)).isoformat()
|
||||
|
||||
@@ -1459,7 +1525,9 @@ class OpsManager:
|
||||
now = datetime.now().isoformat()
|
||||
|
||||
# 基于历史数据预测
|
||||
metrics = self.get_recent_metrics(tenant_id, f"{resource_type.value}_usage", seconds=30 * 24 * 3600)
|
||||
metrics = self.get_recent_metrics(
|
||||
tenant_id, f"{resource_type.value}_usage", seconds=30 * 24 * 3600
|
||||
)
|
||||
|
||||
if metrics:
|
||||
values = [m.metric_value for m in metrics]
|
||||
@@ -1553,7 +1621,8 @@ class OpsManager:
|
||||
"""获取容量规划列表"""
|
||||
with self._get_db() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM capacity_plans WHERE tenant_id = ? ORDER BY created_at DESC", (tenant_id,)
|
||||
"SELECT * FROM capacity_plans WHERE tenant_id = ? ORDER BY created_at DESC",
|
||||
(tenant_id,),
|
||||
).fetchall()
|
||||
return [self._row_to_capacity_plan(row) for row in rows]
|
||||
|
||||
@@ -1629,7 +1698,9 @@ class OpsManager:
|
||||
def get_auto_scaling_policy(self, policy_id: str) -> AutoScalingPolicy | None:
|
||||
"""获取自动扩缩容策略"""
|
||||
with self._get_db() as conn:
|
||||
row = conn.execute("SELECT * FROM auto_scaling_policies WHERE id = ?", (policy_id,)).fetchone()
|
||||
row = conn.execute(
|
||||
"SELECT * FROM auto_scaling_policies WHERE id = ?", (policy_id,)
|
||||
).fetchone()
|
||||
|
||||
if row:
|
||||
return self._row_to_auto_scaling_policy(row)
|
||||
@@ -1639,7 +1710,8 @@ class OpsManager:
|
||||
"""列出租户的自动扩缩容策略"""
|
||||
with self._get_db() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM auto_scaling_policies WHERE tenant_id = ? ORDER BY created_at DESC", (tenant_id,)
|
||||
"SELECT * FROM auto_scaling_policies WHERE tenant_id = ? ORDER BY created_at DESC",
|
||||
(tenant_id,),
|
||||
).fetchall()
|
||||
return [self._row_to_auto_scaling_policy(row) for row in rows]
|
||||
|
||||
@@ -1664,7 +1736,9 @@ class OpsManager:
|
||||
if current_utilization > policy.scale_up_threshold:
|
||||
if current_instances < policy.max_instances:
|
||||
action = ScalingAction.SCALE_UP
|
||||
reason = f"利用率 {current_utilization:.1%} 超过扩容阈值 {policy.scale_up_threshold:.1%}"
|
||||
reason = (
|
||||
f"利用率 {current_utilization:.1%} 超过扩容阈值 {policy.scale_up_threshold:.1%}"
|
||||
)
|
||||
elif current_utilization < policy.scale_down_threshold:
|
||||
if current_instances > policy.min_instances:
|
||||
action = ScalingAction.SCALE_DOWN
|
||||
@@ -1681,7 +1755,12 @@ class OpsManager:
|
||||
return None
|
||||
|
||||
def _create_scaling_event(
|
||||
self, policy: AutoScalingPolicy, action: ScalingAction, from_count: int, to_count: int, reason: str
|
||||
self,
|
||||
policy: AutoScalingPolicy,
|
||||
action: ScalingAction,
|
||||
from_count: int,
|
||||
to_count: int,
|
||||
reason: str,
|
||||
) -> ScalingEvent:
|
||||
"""创建扩缩容事件"""
|
||||
event_id = f"se_{uuid.uuid4().hex[:16]}"
|
||||
@@ -1741,7 +1820,9 @@ class OpsManager:
|
||||
return self._row_to_scaling_event(row)
|
||||
return None
|
||||
|
||||
def update_scaling_event_status(self, event_id: str, status: str, error_message: str = None) -> ScalingEvent | None:
|
||||
def update_scaling_event_status(
|
||||
self, event_id: str, status: str, error_message: str = None
|
||||
) -> ScalingEvent | None:
|
||||
"""更新扩缩容事件状态"""
|
||||
now = datetime.now().isoformat()
|
||||
|
||||
@@ -1777,7 +1858,9 @@ class OpsManager:
|
||||
return self._row_to_scaling_event(row)
|
||||
return None
|
||||
|
||||
def list_scaling_events(self, tenant_id: str, policy_id: str = None, limit: int = 100) -> list[ScalingEvent]:
|
||||
def list_scaling_events(
|
||||
self, tenant_id: str, policy_id: str = None, limit: int = 100
|
||||
) -> list[ScalingEvent]:
|
||||
"""列出租户的扩缩容事件"""
|
||||
query = "SELECT * FROM scaling_events WHERE tenant_id = ?"
|
||||
params = [tenant_id]
|
||||
@@ -1873,7 +1956,8 @@ class OpsManager:
|
||||
"""列出租户的健康检查"""
|
||||
with self._get_db() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM health_checks WHERE tenant_id = ? ORDER BY created_at DESC", (tenant_id,)
|
||||
"SELECT * FROM health_checks WHERE tenant_id = ? ORDER BY created_at DESC",
|
||||
(tenant_id,),
|
||||
).fetchall()
|
||||
return [self._row_to_health_check(row) for row in rows]
|
||||
|
||||
@@ -1947,7 +2031,11 @@ class OpsManager:
|
||||
if response.status_code == expected_status:
|
||||
return HealthStatus.HEALTHY, response_time, "OK"
|
||||
else:
|
||||
return HealthStatus.DEGRADED, response_time, f"Unexpected status: {response.status_code}"
|
||||
return (
|
||||
HealthStatus.DEGRADED,
|
||||
response_time,
|
||||
f"Unexpected status: {response.status_code}",
|
||||
)
|
||||
except Exception as e:
|
||||
return HealthStatus.UNHEALTHY, (time.time() - start_time) * 1000, str(e)
|
||||
|
||||
@@ -1962,7 +2050,9 @@ class OpsManager:
|
||||
|
||||
start_time = time.time()
|
||||
try:
|
||||
reader, writer = await asyncio.wait_for(asyncio.open_connection(host, port), timeout=check.timeout)
|
||||
reader, writer = await asyncio.wait_for(
|
||||
asyncio.open_connection(host, port), timeout=check.timeout
|
||||
)
|
||||
response_time = (time.time() - start_time) * 1000
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
@@ -2057,7 +2147,9 @@ class OpsManager:
|
||||
def get_failover_config(self, config_id: str) -> FailoverConfig | None:
|
||||
"""获取故障转移配置"""
|
||||
with self._get_db() as conn:
|
||||
row = conn.execute("SELECT * FROM failover_configs WHERE id = ?", (config_id,)).fetchone()
|
||||
row = conn.execute(
|
||||
"SELECT * FROM failover_configs WHERE id = ?", (config_id,)
|
||||
).fetchone()
|
||||
|
||||
if row:
|
||||
return self._row_to_failover_config(row)
|
||||
@@ -2067,7 +2159,8 @@ class OpsManager:
|
||||
"""列出租户的故障转移配置"""
|
||||
with self._get_db() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM failover_configs WHERE tenant_id = ? ORDER BY created_at DESC", (tenant_id,)
|
||||
"SELECT * FROM failover_configs WHERE tenant_id = ? ORDER BY created_at DESC",
|
||||
(tenant_id,),
|
||||
).fetchall()
|
||||
return [self._row_to_failover_config(row) for row in rows]
|
||||
|
||||
@@ -2256,7 +2349,8 @@ class OpsManager:
|
||||
"""列出租户的备份任务"""
|
||||
with self._get_db() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM backup_jobs WHERE tenant_id = ? ORDER BY created_at DESC", (tenant_id,)
|
||||
"SELECT * FROM backup_jobs WHERE tenant_id = ? ORDER BY created_at DESC",
|
||||
(tenant_id,),
|
||||
).fetchall()
|
||||
return [self._row_to_backup_job(row) for row in rows]
|
||||
|
||||
@@ -2334,7 +2428,9 @@ class OpsManager:
|
||||
return self._row_to_backup_record(row)
|
||||
return None
|
||||
|
||||
def list_backup_records(self, tenant_id: str, job_id: str = None, limit: int = 100) -> list[BackupRecord]:
|
||||
def list_backup_records(
|
||||
self, tenant_id: str, job_id: str = None, limit: int = 100
|
||||
) -> list[BackupRecord]:
|
||||
"""列出租户的备份记录"""
|
||||
query = "SELECT * FROM backup_records WHERE tenant_id = ?"
|
||||
params = [tenant_id]
|
||||
@@ -2379,7 +2475,9 @@ class OpsManager:
|
||||
# 简化计算:假设每单位资源每月成本
|
||||
unit_cost = 10.0
|
||||
resource_cost = unit_cost * util.utilization_rate
|
||||
breakdown[util.resource_type.value] = breakdown.get(util.resource_type.value, 0) + resource_cost
|
||||
breakdown[util.resource_type.value] = (
|
||||
breakdown.get(util.resource_type.value, 0) + resource_cost
|
||||
)
|
||||
total_cost += resource_cost
|
||||
|
||||
# 检测异常
|
||||
@@ -2457,7 +2555,11 @@ class OpsManager:
|
||||
def _calculate_cost_trends(self, tenant_id: str, year: int, month: int) -> dict:
|
||||
"""计算成本趋势"""
|
||||
# 简化实现:返回模拟趋势
|
||||
return {"month_over_month": 0.05, "year_over_year": 0.15, "forecast_next_month": 1.05} # 5% 增长 # 15% 增长
|
||||
return {
|
||||
"month_over_month": 0.05,
|
||||
"year_over_year": 0.15,
|
||||
"forecast_next_month": 1.05,
|
||||
} # 5% 增长 # 15% 增长
|
||||
|
||||
def record_resource_utilization(
|
||||
self,
|
||||
@@ -2512,7 +2614,9 @@ class OpsManager:
|
||||
|
||||
return util
|
||||
|
||||
def get_resource_utilizations(self, tenant_id: str, report_period: str) -> list[ResourceUtilization]:
|
||||
def get_resource_utilizations(
|
||||
self, tenant_id: str, report_period: str
|
||||
) -> list[ResourceUtilization]:
|
||||
"""获取资源利用率列表"""
|
||||
with self._get_db() as conn:
|
||||
rows = conn.execute(
|
||||
@@ -2590,11 +2694,14 @@ class OpsManager:
|
||||
"""获取闲置资源列表"""
|
||||
with self._get_db() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM idle_resources WHERE tenant_id = ? ORDER BY detected_at DESC", (tenant_id,)
|
||||
"SELECT * FROM idle_resources WHERE tenant_id = ? ORDER BY detected_at DESC",
|
||||
(tenant_id,),
|
||||
).fetchall()
|
||||
return [self._row_to_idle_resource(row) for row in rows]
|
||||
|
||||
def generate_cost_optimization_suggestions(self, tenant_id: str) -> list[CostOptimizationSuggestion]:
|
||||
def generate_cost_optimization_suggestions(
|
||||
self, tenant_id: str
|
||||
) -> list[CostOptimizationSuggestion]:
|
||||
"""生成成本优化建议"""
|
||||
suggestions = []
|
||||
|
||||
@@ -2677,7 +2784,9 @@ class OpsManager:
|
||||
rows = conn.execute(query, params).fetchall()
|
||||
return [self._row_to_cost_optimization_suggestion(row) for row in rows]
|
||||
|
||||
def apply_cost_optimization_suggestion(self, suggestion_id: str) -> CostOptimizationSuggestion | None:
|
||||
def apply_cost_optimization_suggestion(
|
||||
self, suggestion_id: str
|
||||
) -> CostOptimizationSuggestion | None:
|
||||
"""应用成本优化建议"""
|
||||
now = datetime.now().isoformat()
|
||||
|
||||
@@ -2694,10 +2803,14 @@ class OpsManager:
|
||||
|
||||
return self.get_cost_optimization_suggestion(suggestion_id)
|
||||
|
||||
def get_cost_optimization_suggestion(self, suggestion_id: str) -> CostOptimizationSuggestion | None:
|
||||
def get_cost_optimization_suggestion(
|
||||
self, suggestion_id: str
|
||||
) -> CostOptimizationSuggestion | None:
|
||||
"""获取成本优化建议详情"""
|
||||
with self._get_db() as conn:
|
||||
row = conn.execute("SELECT * FROM cost_optimization_suggestions WHERE id = ?", (suggestion_id,)).fetchone()
|
||||
row = conn.execute(
|
||||
"SELECT * FROM cost_optimization_suggestions WHERE id = ?", (suggestion_id,)
|
||||
).fetchone()
|
||||
|
||||
if row:
|
||||
return self._row_to_cost_optimization_suggestion(row)
|
||||
@@ -2980,9 +3093,11 @@ class OpsManager:
|
||||
applied_at=row["applied_at"],
|
||||
)
|
||||
|
||||
|
||||
# Singleton instance
|
||||
_ops_manager = None
|
||||
|
||||
|
||||
def get_ops_manager() -> OpsManager:
|
||||
global _ops_manager
|
||||
if _ops_manager is None:
|
||||
|
||||
Reference in New Issue
Block a user