init: EZOps AIOps 智能运维平台

- 前端: React 18 + TypeScript + Vite + Tailwind CSS + shadcn/ui
- 后端: Go + Gin + GORM + JWT (golang-jwt/jwt/v5)
- 功能: 服务器管理、K8s集群、监控告警、CI/CD、自动化运维、审批流程、审计日志
- 文档: 设计文档(ROADMAP/PDD/架构/模块)
This commit is contained in:
attacker committed 2026-06-13 23:09:47 +08:00
commit 7d6674bddd
156 files changed
+45704

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
-- EZOps 数据库初始化脚本
-- 创建数据库
CREATE DATABASE IF NOT EXISTS ezops CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE ezops;
-- 创建初始管理员用户
-- 密码: admin123 (bcrypt hash)
INSERT INTO users (username, password, email, real_name, phone, status, is_admin, created_at, updated_at) VALUES
('admin', '$2a$10$N9qo8uLOickgx2ZMRZoMy.MqrqQzBZN0UfGNEsKYGsGqNQJx3wDxG', 'admin@ezops.local', '系统管理员', '13800138000', 'active', true, NOW(), NOW())
ON DUPLICATE KEY UPDATE updated_at = NOW();
-- 创建默认角色
INSERT INTO roles (name, description, created_at, updated_at) VALUES
('超级管理员', '拥有所有权限', NOW(), NOW()),
('运维工程师', '运维操作权限', NOW(), NOW()),
('开发人员', '开发相关权限', NOW(), NOW()),
('只读用户', '只读查看权限', NOW(), NOW())
ON DUPLICATE KEY UPDATE updated_at = NOW();
-- 创建默认权限
INSERT INTO permissions (name, resource, action, created_at, updated_at) VALUES
('用户管理', 'user', 'manage', NOW(), NOW()),
('服务器管理', 'server', 'manage', NOW(), NOW()),
('K8s管理', 'k8s', 'manage', NOW(), NOW()),
('监控告警', 'alert', 'manage', NOW(), NOW()),
('应用发布', 'pipeline', 'manage', NOW(), NOW()),
('自动化运维', 'automation', 'manage', NOW(), NOW()),
('审批流程', 'approval', 'manage', NOW(), NOW()),
('系统设置', 'system', 'manage', NOW(), NOW())
ON DUPLICATE KEY UPDATE updated_at = NOW();
+354
View File
@@ -0,0 +1,354 @@
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 := generatePipelines(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
}
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"},
{Name: "腾讯云主账号", Provider: "tencent", Status: "active"},
{Name: "AWS 账号", Provider: "aws", Status: "active"},
{Name: "华为云账号", Provider: "huawei", Status: "inactive"},
}
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, 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, 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, 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, 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
}
}
}
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++ {
event := models.AlertEvent{
RuleID: rules[rand.Intn(len(rules))].ID,
RuleName: rules[rand.Intn(len(rules))].Name,
Severity: []string{"info", "warning", "critical"}[rand.Intn(3)],
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 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 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 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)
}