645 lines
25 KiB
Go
645 lines
25 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"time"
|
|
|
|
"ezops/internal/config"
|
|
"ezops/internal/models"
|
|
"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 := generateK8sClusters(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 := []models.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([]models.Server, 0, 50)
|
|
for i := 0; i < 50; i++ {
|
|
server := models.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 := []models.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 := []models.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 generateK8sClusters(db *gorm.DB) error {
|
|
clusters := []models.K8sCluster{
|
|
{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 := models.K8sNode{
|
|
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 := models.K8sDeployment{
|
|
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 := models.K8sPod{
|
|
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 := models.K8sService{
|
|
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 := models.K8sIngress{
|
|
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 := []models.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 := models.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 := []models.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 := []models.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 := models.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([]models.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 := models.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 := []models.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 := []models.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 := []models.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 := []models.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 := []models.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 []models.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, models.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 := []models.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)
|
|
}
|