Files
aiops/backend/controller/zabbix_datasource.go
T
2026-07-09 14:16:56 +08:00

230 lines
6.5 KiB
Go

package controller
import (
"context"
"net/http"
"time"
"ezops/model"
"ezops/pkg/zabbix"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// ZabbixDSHandler Zabbix 数据源管理 handler // Logan.Li
type ZabbixDSHandler struct {
db *gorm.DB
}
// NewZabbixDSHandler 创建 Zabbix 数据源 handler
func NewZabbixDSHandler(db *gorm.DB) *ZabbixDSHandler {
return &ZabbixDSHandler{db: db}
}
// ============================================
// CRUD
// ============================================
// List 数据源列表
// GET /api/v1/zabbix-datasources
func (h *ZabbixDSHandler) List(c *gin.Context) {
var sources []model.ZabbixDataSource
if err := h.db.Order("is_default DESC, id ASC").Find(&sources).Error; err != nil {
c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "查询失败: " + err.Error()})
return
}
if sources == nil {
sources = []model.ZabbixDataSource{}
}
c.JSON(http.StatusOK, model.Response{Code: 200, Data: sources})
}
// Get 获取单个数据源
// GET /api/v1/zabbix-datasources/:id
func (h *ZabbixDSHandler) Get(c *gin.Context) {
id := c.Param("id")
var ds model.ZabbixDataSource
if err := h.db.First(&ds, id).Error; err != nil {
c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "数据源不存在"})
return
}
c.JSON(http.StatusOK, model.Response{Code: 200, Data: ds})
}
// Create 创建数据源
// POST /api/v1/zabbix-datasources
func (h *ZabbixDSHandler) Create(c *gin.Context) {
var req model.CreateZabbixDSReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "参数错误: " + err.Error()})
return
}
if req.IsDefault {
h.db.Model(&model.ZabbixDataSource{}).Where("is_default = ?", true).Update("is_default", false)
}
ds := model.ZabbixDataSource{
Name: req.Name,
URL: req.URL,
Username: req.Username,
Password: req.Password,
TrendsAfter: req.TrendsAfter,
TrendsRange: req.TrendsRange,
TrendsCacheTTL: req.TrendsCacheTTL,
TrendsTimeout: req.TrendsTimeout,
DirectDB: req.DirectDB,
DisableAcknowledges: req.DisableAcknowledges,
DisableDataAlignment: req.DisableDataAlignment,
IsDefault: req.IsDefault,
Status: 1,
}
if ds.TrendsCacheTTL <= 0 {
ds.TrendsCacheTTL = 3600
}
if ds.TrendsTimeout <= 0 {
ds.TrendsTimeout = 30
}
if err := h.db.Create(&ds).Error; err != nil {
c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "创建失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, model.Response{Code: 200, Data: ds, Message: "创建成功"})
}
// Update 更新数据源
// PUT /api/v1/zabbix-datasources/:id
func (h *ZabbixDSHandler) Update(c *gin.Context) {
id := c.Param("id")
var ds model.ZabbixDataSource
if err := h.db.First(&ds, id).Error; err != nil {
c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "数据源不存在"})
return
}
var req model.UpdateZabbixDSReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "参数错误: " + err.Error()})
return
}
updates := map[string]interface{}{}
if req.Name != nil {
updates["name"] = *req.Name
}
if req.URL != nil {
updates["url"] = *req.URL
}
if req.Username != nil {
updates["username"] = *req.Username
}
if req.Password != nil && *req.Password != "" {
updates["password"] = *req.Password
}
if req.TrendsAfter != nil {
updates["trends_after"] = *req.TrendsAfter
}
if req.TrendsRange != nil {
updates["trends_range"] = *req.TrendsRange
}
if req.TrendsCacheTTL != nil {
updates["trends_cache_ttl"] = *req.TrendsCacheTTL
}
if req.TrendsTimeout != nil {
updates["trends_timeout"] = *req.TrendsTimeout
}
if req.DirectDB != nil {
updates["direct_db"] = *req.DirectDB
}
if req.DisableAcknowledges != nil {
updates["disable_acknowledges"] = *req.DisableAcknowledges
}
if req.DisableDataAlignment != nil {
updates["disable_data_alignment"] = *req.DisableDataAlignment
}
if req.IsDefault != nil {
updates["is_default"] = *req.IsDefault
if *req.IsDefault {
h.db.Model(&model.ZabbixDataSource{}).Where("is_default = ? AND id != ?", true, id).Update("is_default", false)
}
}
if req.Status != nil {
updates["status"] = *req.Status
}
if len(updates) > 0 {
if err := h.db.Model(&ds).Updates(updates).Error; err != nil {
c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "更新失败: " + err.Error()})
return
}
}
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "更新成功"})
}
// Delete 删除数据源
// DELETE /api/v1/zabbix-datasources/:id
func (h *ZabbixDSHandler) Delete(c *gin.Context) {
id := c.Param("id")
if err := h.db.Delete(&model.ZabbixDataSource{}, id).Error; err != nil {
c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "删除失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "已删除"})
}
// SetDefault 设为默认
// POST /api/v1/zabbix-datasources/:id/default
func (h *ZabbixDSHandler) SetDefault(c *gin.Context) {
id := c.Param("id")
h.db.Model(&model.ZabbixDataSource{}).Where("is_default = ?", true).Update("is_default", false)
if err := h.db.Model(&model.ZabbixDataSource{}).Where("id = ?", id).Update("is_default", true).Error; err != nil {
c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "设置失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "已设为默认"})
}
// TestConnection 测试 Zabbix 连接
// POST /api/v1/zabbix-datasources/test
func (h *ZabbixDSHandler) TestConnection(c *gin.Context) {
var req model.TestZabbixDSReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "参数错误: " + err.Error()})
return
}
client := zabbix.NewClient(req.URL, req.Username, req.Password,
zabbix.WithHTTPTimeout(10*time.Second),
)
ctx, cancel := context.WithTimeout(context.Background(), 12*time.Second)
defer cancel()
if err := client.Auth(ctx); err != nil {
c.JSON(http.StatusOK, model.Response{
Code: 200,
Data: map[string]interface{}{
"success": false,
"message": "认证失败: " + err.Error(),
},
})
return
}
token := client.GetAuthToken()
c.JSON(http.StatusOK, model.Response{
Code: 200,
Data: map[string]interface{}{
"success": true,
"message": "连接成功,Zabbix 认证通过",
"session_id": token,
},
})
}