Files
attacker 77c234b060 feat(audit): F1+F2 告警静默规则标记完成 + 审计日志CSV导出实现
F1 告警静默规则 [done]:
- 后端 alert_silence.go: CRUD + Toggle (onetime/daily/weekly 三模式)
- 告警引擎 isSilenced 集成 (alert_engine.go)
- 前端 SilenceRuleTab + SilenceDialog
- 路由 /alerts/silences 已注册

F2 审计日志导出 [done]:
- 重写 ExportAuditLogs: 真正的 CSV 导出 (encoding/csv + UTF-8 BOM)
- 支持 module/action/username/startTime/endTime 筛选
- 导出限制 10000 条防溢出,自动记录审计日志
- JSON 格式向后兼容 (format=json)
- 前端 exportLogs 传递查询参数

同时包含累积的前期工作:
- 目录重构 internal/ -> controller/model/router (v0.55-v0.57)
- 后端分层架构 dto/repository/service/utils
- 审计模块全功能 (终端审计/操作审计/登录日志)
- asciicast v2 录制格式
- SFTP 文件浏览器
- StatStrip 紧凑统计条
- 在线会话自动刷新
- LiveMonitor WebSocket 诊断修复

验证: go build ✅ | npm run build ✅ | Docker 部署 ✅ | 10 回归端点 ✅ | CSV 导出 ✅ | 静默 CRUD ✅
2026-06-25 20:16:30 +08:00

645 lines
25 KiB
Go

package main
import (
"fmt"
"math/rand"
"time"
"ezops/config"
"ezops/model"
"ezops/pkg/database"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
func main() {
cfg := config.Load()
db, err := database.New(cfg.Database)
if err != nil {
fmt.Printf("Failed to connect to database: %v\n", err)
return
}
if err := generateMockData(db); err != nil {
fmt.Printf("Failed to generate mock data: %v\n", err)
return
}
fmt.Println("Mock data generated successfully!")
}
func generateMockData(db *gorm.DB) error {
if err := generateUsers(db); err != nil {
return err
}
if err := generateServers(db); err != nil {
return err
}
if err := generateCloudAccounts(db); err != nil {
return err
}
if err := generateDomains(db); err != nil {
return err
}
if err := generateKubernetesClusters(db); err != nil {
return err
}
if err := generateAlertRules(db); err != nil {
return err
}
if err := generateNotifyChannels(db); err != nil {
return err
}
if err := generatePipelines(db); err != nil {
return err
}
if err := generateAppReleases(db); err != nil {
return err
}
if err := generateCronJobs(db); err != nil {
return err
}
if err := generateScripts(db); err != nil {
return err
}
if err := generateApprovalTemplates(db); err != nil {
return err
}
if err := generateNavigations(db); err != nil {
return err
}
if err := generateBillings(db); err != nil {
return err
}
return nil
}
func generateUsers(db *gorm.DB) error {
users := []model.User{
{Username: "admin", Email: "admin@ezops.local", RealName: "系统管理员", Phone: "13800138000", Status: 1, IsAdmin: true},
{Username: "ops01", Email: "ops01@ezops.local", RealName: "运维工程师1", Phone: "13800138001", Status: 1, IsAdmin: false},
{Username: "ops02", Email: "ops02@ezops.local", RealName: "运维工程师2", Phone: "13800138002", Status: 1, IsAdmin: false},
{Username: "dev01", Email: "dev01@ezops.local", RealName: "开发工程师1", Phone: "13800138003", Status: 1, IsAdmin: false},
{Username: "dev02", Email: "dev02@ezops.local", RealName: "开发工程师2", Phone: "13800138004", Status: 0, IsAdmin: false},
}
password, _ := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost)
for i := range users {
users[i].Password = string(password)
if err := db.Create(&users[i]).Error; err != nil {
return err
}
}
fmt.Println("Generated users:", len(users))
return nil
}
func generateServers(db *gorm.DB) error {
osTypes := []string{"CentOS 7.9", "CentOS 8.5", "Ubuntu 20.04", "Ubuntu 22.04", "Debian 11", "Rocky Linux 8.6"}
statuses := []string{"running", "stopped", "maintenance"}
servers := make([]model.Server, 0, 50)
for i := 0; i < 50; i++ {
server := model.Server{
Hostname: fmt.Sprintf("server-%03d", i+1),
IP: fmt.Sprintf("10.0.%d.%d", rand.Intn(256), rand.Intn(256)),
PublicIP: fmt.Sprintf("47.%d.%d.%d", rand.Intn(256), rand.Intn(256), rand.Intn(256)),
OS: osTypes[rand.Intn(len(osTypes))],
CPU: []int{2, 4, 8, 16, 32}[rand.Intn(5)],
Memory: []int64{4096, 8192, 16384, 32768, 65536, 131072}[rand.Intn(6)],
Disk: []int64{100, 200, 500, 1000}[rand.Intn(4)],
Status: statuses[rand.Intn(len(statuses))],
CPUUsage: rand.Float64() * 80,
MemoryUsage: rand.Float64() * 80,
DiskUsage: rand.Float64() * 70,
Tags: fmt.Sprintf("{\"project\":\"project%d\",\"team\":\"team%d\"}", rand.Intn(10), rand.Intn(5)),
Description: fmt.Sprintf("服务器 %d 描述", i+1),
}
servers = append(servers, server)
}
if err := db.Create(&servers).Error; err != nil {
return err
}
fmt.Println("Generated servers:", len(servers))
return nil
}
func generateCloudAccounts(db *gorm.DB) error {
accounts := []model.CloudAccount{
{Name: "阿里云主账号", Provider: "aliyun", Status: "active", MonthlyCost: 28500},
{Name: "腾讯云主账号", Provider: "tencent", Status: "active", MonthlyCost: 15800},
{Name: "AWS 账号", Provider: "aws", Status: "active", MonthlyCost: 42000},
{Name: "华为云账号", Provider: "huawei", Status: "inactive", MonthlyCost: 8900},
}
for i := range accounts {
accounts[i].AccessKey = "LTAI" + randomString(16)
accounts[i].SecretKey = randomString(32)
if err := db.Create(&accounts[i]).Error; err != nil {
return err
}
}
fmt.Println("Generated cloud accounts:", len(accounts))
return nil
}
func generateDomains(db *gorm.DB) error {
domains := []model.Domain{
{Name: "ezops.local", Registrar: "aliyun", Status: "active", DNSProvider: "alidns"},
{Name: "api.ezops.local", Registrar: "aliyun", Status: "active", DNSProvider: "alidns"},
{Name: "app.ezops.local", Registrar: "tencent", Status: "active", DNSProvider: "dnspod"},
{Name: "monitor.ezops.local", Registrar: "aliyun", Status: "active", DNSProvider: "alidns", SSLEnabled: true},
}
for i := range domains {
expireDays := rand.Intn(365) + 30
expireDate := time.Now().AddDate(0, 0, expireDays)
domains[i].ExpireDate = &expireDate
domains[i].SSLExpireDate = &expireDate
if err := db.Create(&domains[i]).Error; err != nil {
return err
}
}
fmt.Println("Generated domains:", len(domains))
return nil
}
func generateKubernetesClusters(db *gorm.DB) error {
clusters := []model.KubernetesCluster{
{Name: "prod-cluster", Code: "prod", Version: "v1.28.0", Status: "healthy", NodeCount: 10, PodCount: 150, ServiceCount: 30, DeploymentCount: 15, APIEndpoint: "https://prod-api.ezops.local:6443", CPUUsage: 65.5, MemoryUsage: 72.3, Description: "生产环境 Kubernetes 集群"},
{Name: "staging-cluster", Code: "staging", Version: "v1.28.0", Status: "healthy", NodeCount: 5, PodCount: 80, ServiceCount: 15, DeploymentCount: 10, APIEndpoint: "https://staging-api.ezops.local:6443", CPUUsage: 45.2, MemoryUsage: 55.0, Description: "预发环境 Kubernetes 集群"},
{Name: "dev-cluster", Code: "dev", Version: "v1.27.0", Status: "warning", NodeCount: 3, PodCount: 45, ServiceCount: 8, DeploymentCount: 8, APIEndpoint: "https://dev-api.ezops.local:6443", CPUUsage: 80.1, MemoryUsage: 85.0, Description: "开发环境 Kubernetes 集群"},
{Name: "test-cluster", Code: "test", Version: "v1.27.0", Status: "error", NodeCount: 2, PodCount: 20, ServiceCount: 5, DeploymentCount: 5, APIEndpoint: "https://test-api.ezops.local:6443", CPUUsage: 30.0, MemoryUsage: 40.0, Description: "测试环境 Kubernetes 集群"},
}
for i := range clusters {
if err := db.Create(&clusters[i]).Error; err != nil {
return err
}
}
for _, cluster := range clusters {
// 生成节点
for j := 0; j < cluster.NodeCount; j++ {
node := model.KubernetesNode{
ClusterID: cluster.ID,
Name: fmt.Sprintf("%s-node-%d", cluster.Code, j+1),
IP: fmt.Sprintf("192.168.%d.%d", rand.Intn(256), rand.Intn(256)),
Status: []string{"Ready", "Ready", "Ready", "NotReady"}[rand.Intn(4)],
Role: []string{"master", "worker", "worker"}[rand.Intn(3)],
CPU: []int{4, 8, 16}[rand.Intn(3)],
Memory: []int64{16384, 32768, 65536}[rand.Intn(3)],
Disk: []int64{100, 200, 500}[rand.Intn(3)],
CPUUsage: rand.Float64() * 80,
MemoryUsage: rand.Float64() * 80,
DiskUsage: rand.Float64() * 70,
PodCount: rand.Intn(30) + 5,
MaxPods: 110,
OS: "Ubuntu 22.04.3 LTS",
KubeletVer: cluster.Version,
}
if err := db.Create(&node).Error; err != nil {
return err
}
}
// 生成 Deployments
depImages := []string{
"nginx:1.25.3", "redis:7.2-alpine", "mysql:8.0.35",
"kafka:3.6.0", "elasticsearch:8.11.0", "grafana/grafana:10.2.0",
"prom/prometheus:v2.48.0", "busybox:1.36", "easzlab/kubeasz:3.6.1",
}
depNames := []string{
"nginx-deploy", "redis-cluster", "mysql-master", "mysql-slave",
"kafka-broker", "es-cluster", "grafana", "prometheus",
"filebeat", "logstash", "jaeger", "zipkin",
"frontend", "backend-api", "gateway",
}
namespaces := []string{"default", "kube-system", "monitoring", "ingress-nginx", "production"}
numDeps := cluster.DeploymentCount
if numDeps < 5 {
numDeps = 5 + rand.Intn(10)
}
for d := 0; d < numDeps && d < len(depNames); d++ {
replicas := []int{1, 2, 3, 5}[rand.Intn(4)]
available := replicas
if rand.Intn(4) == 0 {
available = replicas - 1
}
if available < 0 {
available = 0
}
dep := model.KubernetesDeployment{
ClusterID: cluster.ID,
Namespace: namespaces[rand.Intn(len(namespaces))],
Name: depNames[d],
Replicas: replicas,
AvailableReplicas: available,
ReadyReplicas: available,
Image: depImages[rand.Intn(len(depImages))],
Strategy: "RollingUpdate",
}
if err := db.Create(&dep).Error; err != nil {
return err
}
}
// 生成 Pods
podStatuses := []string{"Running", "Running", "Running", "Running", "Pending", "CrashLoopBackOff"}
numPods := cluster.PodCount
if numPods > 30 {
numPods = 30
}
if numPods < 10 {
numPods = 10 + rand.Intn(15)
}
for p := 0; p < numPods; p++ {
status := podStatuses[rand.Intn(len(podStatuses))]
pod := model.KubernetesPod{
ClusterID: cluster.ID,
Namespace: namespaces[rand.Intn(len(namespaces))],
Name: fmt.Sprintf("%s-pod-%d", cluster.Code, p+1),
Status: status,
NodeName: fmt.Sprintf("%s-node-%d", cluster.Code, rand.Intn(cluster.NodeCount)+1),
IP: fmt.Sprintf("10.%d.%d.%d", rand.Intn(256), rand.Intn(256), rand.Intn(256)),
RestartCount: rand.Intn(10),
Image: depImages[rand.Intn(len(depImages))],
CPUUsage: rand.Float64() * 500,
MemoryUsage: rand.Float64() * 2048,
}
if err := db.Create(&pod).Error; err != nil {
return err
}
}
// 生成 Services
svcTypes := []string{"ClusterIP", "NodePort", "LoadBalancer"}
svcNames := []string{
"nginx-svc", "redis-svc", "mysql-svc", "kafka-svc",
"es-svc", "grafana-svc", "prometheus-svc",
"frontend-svc", "backend-svc", "gateway-svc",
}
numSvcs := cluster.ServiceCount
if numSvcs > 10 {
numSvcs = 10
}
if numSvcs < 5 {
numSvcs = 5 + rand.Intn(5)
}
for s := 0; s < numSvcs && s < len(svcNames); s++ {
svcType := svcTypes[rand.Intn(len(svcTypes))]
ports := "[]"
switch rand.Intn(4) {
case 0:
ports = `[{"port":80,"protocol":"TCP","targetPort":80}]`
case 1:
ports = `[{"port":443,"protocol":"TCP","targetPort":8443}]`
case 2:
ports = `[{"port":8080,"protocol":"TCP","targetPort":8080},{"port":9090,"protocol":"TCP","targetPort":9090}]`
default:
ports = `[{"port":3306,"protocol":"TCP","targetPort":3306}]`
}
svc := model.KubernetesService{
ClusterID: cluster.ID,
Namespace: namespaces[rand.Intn(len(namespaces))],
Name: svcNames[s],
Type: svcType,
ClusterIP: fmt.Sprintf("10.96.%d.%d", rand.Intn(256), rand.Intn(256)),
ExternalIP: "",
Ports: ports,
Selector: fmt.Sprintf(`{"app":"%s"}`, svcNames[s]),
}
if svcType == "LoadBalancer" {
svc.ExternalIP = fmt.Sprintf("203.0.113.%d", rand.Intn(256))
}
if svcType == "NodePort" {
svc.ExternalIP = fmt.Sprintf("%d-%d", 30000+rand.Intn(1000), 32767)
}
if err := db.Create(&svc).Error; err != nil {
return err
}
}
// 生成 Ingresses
ingNames := []string{"main-ingress", "api-ingress", "grafana-ingress", "canary-ingress"}
numIngs := 2 + rand.Intn(3)
for ig := 0; ig < numIngs && ig < len(ingNames); ig++ {
hosts := fmt.Sprintf(`["%s.ezops.local"]`, ingNames[ig])
ing := model.KubernetesIngress{
ClusterID: cluster.ID,
Namespace: namespaces[rand.Intn(len(namespaces))],
Name: ingNames[ig],
Hosts: hosts,
Backend: fmt.Sprintf("%s-svc:80", ingNames[ig]),
TLS: rand.Intn(2) == 0,
}
if err := db.Create(&ing).Error; err != nil {
return err
}
}
}
fmt.Println("Generated K8s clusters:", len(clusters))
return nil
}
func generateAlertRules(db *gorm.DB) error {
rules := []model.AlertRule{
{Name: "CPU 使用率告警", Type: "metric", Source: "prometheus", Expression: "cpu_usage > 80", Severity: "warning", Duration: 300, Enabled: true, Description: "CPU 使用率超过 80%"},
{Name: "CPU 使用率严重告警", Type: "metric", Source: "prometheus", Expression: "cpu_usage > 95", Severity: "critical", Duration: 120, Enabled: true, Description: "CPU 使用率超过 95%"},
{Name: "内存使用率告警", Type: "metric", Source: "prometheus", Expression: "memory_usage > 80", Severity: "warning", Duration: 300, Enabled: true, Description: "内存使用率超过 80%"},
{Name: "磁盘使用率告警", Type: "metric", Source: "prometheus", Expression: "disk_usage > 80", Severity: "warning", Duration: 600, Enabled: true, Description: "磁盘使用率超过 80%"},
{Name: "服务不可用告警", Type: "event", Source: "custom", Expression: "service_up == 0", Severity: "critical", Duration: 60, Enabled: true, Description: "服务不可用"},
{Name: "Pod 重启告警", Type: "event", Source: "kubernetes", Expression: "pod_restart > 5", Severity: "warning", Duration: 600, Enabled: true, Description: "Pod 重启次数超过 5 次"},
}
for i := range rules {
if err := db.Create(&rules[i]).Error; err != nil {
return err
}
}
for i := 0; i < 20; i++ {
rule := rules[rand.Intn(len(rules))]
event := model.AlertEvent{
RuleID: rule.ID,
RuleName: rule.Name,
Severity: rule.Severity,
Status: []string{"firing", "resolved"}[rand.Intn(2)],
Target: fmt.Sprintf("server-%03d", rand.Intn(50)+1),
Message: fmt.Sprintf("告警事件 %d", i+1),
Value: rand.Float64() * 100,
StartedAt: time.Now().Add(-time.Duration(rand.Intn(72)) * time.Hour),
}
if err := db.Create(&event).Error; err != nil {
return err
}
}
fmt.Println("Generated alert rules:", len(rules))
return nil
}
func generateNotifyChannels(db *gorm.DB) error {
channels := []model.NotifyChannel{
{Name: "运维邮件通知", Type: "email", Config: `{"recipients":["ops@ezops.com","admin@ezops.com"],"subject":"[AIOps告警]"}`, Enabled: true, TestStatus: "success"},
{Name: "短信通知", Type: "sms", Config: `{"phones":["13800138000","13900139000"],"template":"告警:{{alert_name}}"}`, Enabled: true, TestStatus: "success"},
{Name: "钉钉机器人", Type: "dingtalk", Config: `{"webhook":"https://oapi.dingtalk.com/robot/send?access_token=eZOps***","secret":"SEC***","at_all":false}`, Enabled: true, TestStatus: "success"},
{Name: "企业微信机器人", Type: "wechat", Config: `{"webhook":"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=eZOps***"}`, Enabled: true, TestStatus: "success"},
{Name: "通用Webhook", Type: "webhook", Config: `{"url":"https://api.ezops.com/alerts/webhook","method":"POST","headers":{"Authorization":"Bearer ***"}}`, Enabled: false, TestStatus: "pending"},
}
for i := range channels {
if err := db.Create(&channels[i]).Error; err != nil {
return err
}
}
fmt.Println("Generated notify channels:", len(channels))
return nil
}
func generatePipelines(db *gorm.DB) error {
pipelines := []model.Pipeline{
{Name: "前端构建", Code: "frontend-build", Type: "build", Source: "https://gitlab.com/ezops/frontend", Branch: "main", Enabled: true, Description: "前端项目构建流水线"},
{Name: "后端构建", Code: "backend-build", Type: "build", Source: "https://gitlab.com/ezops/backend", Branch: "main", Enabled: true, Description: "后端项目构建流水线"},
{Name: "部署预发", Code: "deploy-staging", Type: "deploy", Source: "https://gitlab.com/ezops/deploy", Branch: "staging", Enabled: true, Description: "部署到预发环境"},
{Name: "部署生产", Code: "deploy-production", Type: "deploy", Source: "https://gitlab.com/ezops/deploy", Branch: "main", Enabled: true, Description: "部署到生产环境"},
{Name: "集成测试", Code: "integration-test", Type: "test", Source: "https://gitlab.com/ezops/tests", Branch: "main", Enabled: true, Description: "集成测试流水线"},
}
for i := range pipelines {
if err := db.Create(&pipelines[i]).Error; err != nil {
return err
}
}
for _, pipeline := range pipelines {
for j := 0; j < 5; j++ {
run := model.PipelineRun{
PipelineID: pipeline.ID,
BuildNumber: j + 1,
Status: []string{"success", "success", "success", "failed", "running"}[rand.Intn(5)],
Branch: pipeline.Branch,
CommitID: randomString(8),
CommitMsg: "Update " + randomString(6),
Author: []string{"admin", "ops01", "dev01"}[rand.Intn(3)],
TriggeredBy: []string{"admin", "ops01", "dev01"}[rand.Intn(3)],
}
if err := db.Create(&run).Error; err != nil {
return err
}
}
}
fmt.Println("Generated pipelines:", len(pipelines))
return nil
}
func generateAppReleases(db *gorm.DB) error {
apps := []string{"AIOps 前端", "AIOps 后端", "用户中心", "支付网关", "数据分析平台"}
environments := []string{"dev", "test", "staging", "prod"}
statuses := []string{"pending", "building", "deploying", "success", "success", "success", "failed", "rolled_back"}
authors := []string{"admin", "ops01", "dev01"}
releases := make([]model.AppRelease, 0, 10)
for i := 0; i < 10; i++ {
app := apps[i%len(apps)]
env := environments[rand.Intn(len(environments))]
status := statuses[rand.Intn(len(statuses))]
minor := rand.Intn(20)
patch := rand.Intn(10)
release := model.AppRelease{
AppName: app,
Version: fmt.Sprintf("v1.%d.%d", minor, patch),
Environment: env,
Status: status,
CommitID: randomString(8),
CommitMsg: fmt.Sprintf("feat: 更新 %s 功能", app),
Author: authors[rand.Intn(len(authors))],
Duration: rand.Intn(600) + 60,
Description: fmt.Sprintf("%s %s 环境发布", app, env),
}
// Set timestamps and approval fields based on status
now := time.Now()
hoursAgo := time.Duration(rand.Intn(168)+1) * time.Hour
if status == "success" || status == "failed" {
approver := authors[rand.Intn(len(authors))]
release.Approver = approver
approvedAt := now.Add(-hoursAgo + 30*time.Minute)
release.ApprovedAt = &approvedAt
deployedAt := now.Add(-hoursAgo + 2*time.Hour)
release.DeployedAt = &deployedAt
} else if status == "rolled_back" {
approver := authors[rand.Intn(len(authors))]
release.Approver = approver
approvedAt := now.Add(-hoursAgo + 30*time.Minute)
release.ApprovedAt = &approvedAt
deployedAt := now.Add(-hoursAgo + 2*time.Hour)
release.DeployedAt = &deployedAt
rollbackAt := now.Add(-hoursAgo + 4*time.Hour)
release.RollbackAt = &rollbackAt
}
releases = append(releases, release)
}
for i := range releases {
if err := db.Create(&releases[i]).Error; err != nil {
return err
}
}
fmt.Println("Generated app releases:", len(releases))
return nil
}
func generateCronJobs(db *gorm.DB) error {
cronJobs := []model.CronJob{
{Name: "数据库备份", CronExpr: "0 2 * * *", Type: "script", Content: "/scripts/backup-db.sh", Enabled: true, Description: "每日凌晨 2 点备份数据库"},
{Name: "清理日志", CronExpr: "0 3 * * 0", Type: "command", Content: "find /var/log -mtime +30 -delete", Enabled: true, Description: "每周日凌晨 3 点清理日志"},
{Name: "数据同步", CronExpr: "*/30 * * * *", Type: "script", Content: "/scripts/sync-data.sh", Enabled: true, Description: "每 30 分钟同步数据"},
{Name: "健康检查", CronExpr: "*/5 * * * *", Type: "command", Content: "curl -sf http://localhost:8080/health", Enabled: true, Description: "每 5 分钟健康检查"},
{Name: "生成报表", CronExpr: "0 9 * * 1", Type: "script", Content: "/scripts/generate-report.sh", Enabled: false, Description: "每周一上午 9 点生成报表"},
}
for i := range cronJobs {
if err := db.Create(&cronJobs[i]).Error; err != nil {
return err
}
}
fmt.Println("Generated cron jobs:", len(cronJobs))
return nil
}
func generateScripts(db *gorm.DB) error {
scripts := []model.Script{
{Name: "重启服务", Code: "restart-service", Type: "shell", Content: "#!/bin/bash\nsystemctl restart $1", Description: "重启服务脚本"},
{Name: "检查磁盘", Code: "check-disk", Type: "shell", Content: "#!/bin/bash\ndf -h", Description: "检查磁盘空间"},
{Name: "检查内存", Code: "check-memory", Type: "shell", Content: "#!/bin/bash\nfree -h", Description: "检查内存使用"},
{Name: "部署应用", Code: "deploy-app", Type: "python", Content: "#!/usr/bin/env python3\nimport sys\nprint(f'Deploying {sys.argv[1]}')", Description: "部署应用脚本"},
{Name: "备份配置", Code: "backup-config", Type: "shell", Content: "#!/bin/bash\ntar -czf /backup/config-$(date +%Y%m%d).tar.gz /etc/ezops", Description: "备份配置文件"},
}
for i := range scripts {
if err := db.Create(&scripts[i]).Error; err != nil {
return err
}
}
fmt.Println("Generated scripts:", len(scripts))
return nil
}
func generateApprovalTemplates(db *gorm.DB) error {
templates := []model.ApprovalTemplate{
{Name: "服务器申请审批", Code: "server-request", Type: "server", Enabled: true, Description: "服务器资源申请审批流程"},
{Name: "发布审批", Code: "release-approval", Type: "release", Enabled: true, Description: "应用发布审批流程"},
{Name: "权限申请审批", Code: "permission-request", Type: "permission", Enabled: true, Description: "系统权限申请审批流程"},
}
for i := range templates {
if err := db.Create(&templates[i]).Error; err != nil {
return err
}
}
fmt.Println("Generated approval templates:", len(templates))
return nil
}
func generateNavigations(db *gorm.DB) error {
groups := []model.NavigationGroup{
{Name: "常用工具", Code: "tools", Icon: "Tool", Sort: 1, Enabled: true},
{Name: "监控平台", Code: "monitor", Icon: "Activity", Sort: 2, Enabled: true},
{Name: "开发工具", Code: "devtools", Icon: "Code", Sort: 3, Enabled: true},
{Name: "文档中心", Code: "docs", Icon: "FileText", Sort: 4, Enabled: true},
}
for i := range groups {
if err := db.Create(&groups[i]).Error; err != nil {
return err
}
}
links := []model.NavigationLink{
{GroupID: groups[0].ID, Name: "GitLab", URL: "https://gitlab.com", Icon: "GitBranch", Description: "代码仓库", Sort: 1},
{GroupID: groups[0].ID, Name: "Jenkins", URL: "https://jenkins.io", Icon: "Settings", Description: "CI/CD 工具", Sort: 2},
{GroupID: groups[0].ID, Name: "Nexus", URL: "https://www.sonatype.com/nexus-repository-oss", Icon: "Package", Description: "制品库", Sort: 3},
{GroupID: groups[1].ID, Name: "Prometheus", URL: "https://prometheus.io", Icon: "Activity", Description: "监控系统", Sort: 1},
{GroupID: groups[1].ID, Name: "Grafana", URL: "https://grafana.com", Icon: "BarChart", Description: "可视化平台", Sort: 2},
{GroupID: groups[1].ID, Name: "ELK", URL: "https://www.elastic.co/what-is/elk-stack", Icon: "Search", Description: "日志分析", Sort: 3},
{GroupID: groups[2].ID, Name: "Swagger", URL: "https://swagger.io", Icon: "FileCode", Description: "API 文档", Sort: 1},
{GroupID: groups[2].ID, Name: "Postman", URL: "https://www.postman.com", Icon: "Send", Description: "API 测试", Sort: 2},
{GroupID: groups[3].ID, Name: "Confluence", URL: "https://www.atlassian.com/software/confluence", Icon: "BookOpen", Description: "知识库", Sort: 1},
}
for i := range links {
if err := db.Create(&links[i]).Error; err != nil {
return err
}
}
fmt.Println("Generated navigation groups:", len(groups))
fmt.Println("Generated navigation links:", len(links))
return nil
}
func generateBillings(db *gorm.DB) error {
accounts := []struct {
ID uint
Name string
Provider string
}{
{1, "阿里云主账号", "aliyun"},
{2, "腾讯云生产环境", "tencent"},
{3, "AWS海外业务", "aws"},
{4, "华为云政务云", "huawei"},
}
services := map[string][]string{
"aliyun": {"ECS云服务器", "RDS数据库", "OSS对象存储", "SLB负载均衡", "CDN加速"},
"tencent": {"CVM云服务器", "CDB数据库", "COS对象存储", "CLB负载均衡", "CDN加速"},
"aws": {"EC2", "RDS", "S3", "CloudFront", "Lambda"},
"huawei": {"ECS弹性云服务器", "RDS数据库", "OBS对象存储", "ELB弹性负载均衡"},
}
now := time.Now()
var billings []model.CloudBilling
// 生成最近60天每天的账单
for day := 59; day >= 0; day-- {
date := now.AddDate(0, 0, -day).Format("2006-01-02")
for _, acc := range accounts {
// 每个账号每天 1-3 条记录(不同服务)
svcs := services[acc.Provider]
count := 1 + rand.Intn(3)
for i := 0; i < count; i++ {
svc := svcs[rand.Intn(len(svcs))]
cost := 50 + rand.Float64()*500
billings = append(billings, model.CloudBilling{
CloudAccountID: &acc.ID,
AccountName: acc.Name,
Provider: acc.Provider,
BillingDate: date,
Cost: cost,
Currency: "CNY",
Service: svc,
})
}
}
}
for i := range billings {
if err := db.Create(&billings[i]).Error; err != nil {
// skip duplicates
continue
}
}
fmt.Println("Generated cloud billings:", len(billings))
// 生成预警规则
rules := []model.BillingAlertRule{
{Name: "每日总成本超500元", Metric: "daily", Threshold: 500, Operator: ">", Enabled: true},
{Name: "阿里云日费用超300元", Provider: "aliyun", Metric: "daily", Threshold: 300, Operator: ">", Enabled: true},
{Name: "月度总成本超1万元", Metric: "monthly", Threshold: 10000, Operator: ">", Enabled: true},
}
for i := range rules {
db.Create(&rules[i])
}
fmt.Println("Generated billing alert rules:", len(rules))
return nil
}
func randomString(length int) string {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length)
for i := range b {
b[i] = charset[rand.Intn(len(charset))]
}
return string(b)
}