后端改进: - 修复 dashboard/recent-alerts 的 limit 参数解析 (原代码错误地将数字解析为日期) - 为 dashboard/recent-releases 添加 limit 参数解析支持 - 新增 generateAppReleases 种子数据生成函数 (10条应用发布记录) - 修复 AlertEvent 的 rule_name/rule_id/severity 数据一致性 - 添加 go-ldap/ldap/v3 依赖并集成 LDAP 认证处理器 - 添加 seed.go 自动种子数据初始化 (admin用户+LDAP配置) - User model 添加 AuthSource/LDAPConfig 字段 前端改进: - 修复 User 类型定义以匹配后端 API (real_name/is_admin/auth_source等) - 修复 Header.tsx 的 real_name 属性引用导致 TypeScript 编译错误 - 统一 API 服务层、暗色主题样式、组件联调优化 验证: - go build ./... 编译通过 - npm run build 构建通过 - 仪表盘发布历史、告警消息等区域数据正常展示 - 健康检查 /health 正常
143 lines
3.0 KiB
Go
143 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"ezops/internal/api/routes"
|
|
"ezops/internal/config"
|
|
"ezops/pkg/database"
|
|
"ezops/pkg/logger"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// 版本信息(通过编译时 ldflags 注入)
|
|
var (
|
|
Version = "dev"
|
|
BuildTime = "unknown"
|
|
GitCommit = "unknown"
|
|
)
|
|
|
|
// @title AIOps运维平台 API
|
|
// @version 1.0
|
|
// @description AIOps智能运维平台后端API文档
|
|
// @termsOfService http://swagger.io/terms/
|
|
|
|
// @contact.name API Support
|
|
// @contact.url http://www.swagger.io/support
|
|
// @contact.email support@swagger.io
|
|
|
|
// @license.name Apache 2.0
|
|
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
|
|
|
// @host localhost:8080
|
|
// @BasePath /api/v1
|
|
|
|
// @securityDefinitions.apikey Bearer
|
|
// @in header
|
|
// @name Authorization
|
|
// @description Type "Bearer" followed by a space and JWT token.
|
|
|
|
func main() {
|
|
// 加载配置
|
|
cfg := config.Load()
|
|
|
|
// 初始化日志
|
|
log := logger.New(cfg.LogLevel)
|
|
defer log.Sync()
|
|
|
|
// 设置Gin模式
|
|
if cfg.Mode == "production" {
|
|
gin.SetMode(gin.ReleaseMode)
|
|
}
|
|
|
|
// 初始化数据库
|
|
db, err := database.New(cfg.Database)
|
|
if err != nil {
|
|
log.Fatal("failed to connect database", zap.Error(err))
|
|
}
|
|
|
|
// 自动迁移
|
|
if err := database.AutoMigrate(db); err != nil {
|
|
log.Fatal("failed to migrate database", zap.Error(err))
|
|
}
|
|
|
|
// 初始化种子数据
|
|
seedData(db)
|
|
|
|
// 创建Gin实例
|
|
r := gin.New()
|
|
|
|
// 中间件
|
|
r.Use(gin.Recovery())
|
|
r.Use(logger.GinLogger(log))
|
|
r.Use(CORS())
|
|
|
|
// 版本信息 API
|
|
r.GET("/version", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"version": Version,
|
|
"build_time": BuildTime,
|
|
"git_commit": GitCommit,
|
|
})
|
|
})
|
|
|
|
// 注册路由
|
|
routes.Register(r, db, log, cfg)
|
|
|
|
// 创建HTTP服务器
|
|
srv := &http.Server{
|
|
Addr: ":" + cfg.Port,
|
|
Handler: r,
|
|
}
|
|
|
|
// 优雅关闭
|
|
go func() {
|
|
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Fatal("failed to start server", zap.Error(err))
|
|
}
|
|
}()
|
|
|
|
log.Info("server started", zap.String("port", cfg.Port))
|
|
|
|
// 等待中断信号
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
<-quit
|
|
|
|
log.Info("shutting down server...")
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
if err := srv.Shutdown(ctx); err != nil {
|
|
log.Fatal("server forced to shutdown", zap.Error(err))
|
|
}
|
|
|
|
log.Info("server exited")
|
|
}
|
|
|
|
// CORS 跨域中间件
|
|
func CORS() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
|
|
c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
|
c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
|
|
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
|
|
if c.Request.Method == "OPTIONS" {
|
|
c.AbortWithStatus(204)
|
|
return
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
}
|