🚀 monitor api

This commit is contained in:
naiba
2024-10-23 23:06:11 +08:00
parent 61e755d2b9
commit 6b650169df
8 changed files with 242 additions and 161 deletions

View File

@@ -62,6 +62,11 @@ func routers(r *gin.Engine) {
auth.POST("/user", commonHandler(createUser))
auth.POST("/batch-delete/user", commonHandler(batchDeleteUser))
auth.GET("/monitor", commonHandler(listMonitor))
auth.POST("/monitor", commonHandler(createMonitor))
auth.PATCH("/monitor/:id", commonHandler(updateMonitor))
auth.POST("/batch-delete/monitor", commonHandler(batchDeleteMonitor))
auth.POST("/server-group", commonHandler(createServerGroup))
auth.PATCH("/server-group/:id", commonHandler(updateServerGroup))
auth.POST("/batch-delete/server-group", commonHandler(batchDeleteServerGroup))

View File

@@ -32,7 +32,6 @@ func (ma *memberAPI) serve() {
// Btn: "点此登录",
// Redirect: "/login",
// }))
mr.POST("/monitor", ma.addOrEditMonitor)
mr.POST("/cron", ma.addOrEditCron)
mr.GET("/cron/:id/manual", ma.manualTrigger)
mr.POST("/force-update", ma.forceUpdate)
@@ -179,12 +178,7 @@ func (ma *memberAPI) delete(c *gin.Context) {
if err == nil {
singleton.OnNATUpdate()
}
case "monitor":
err = singleton.DB.Unscoped().Delete(&model.Monitor{}, "id = ?", id).Error
if err == nil {
singleton.ServiceSentinelShared.OnMonitorDelete(id)
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ?", id).Error
}
case "cron":
err = singleton.DB.Unscoped().Delete(&model.Cron{}, "id = ?", id).Error
if err == nil {
@@ -214,87 +208,6 @@ func (ma *memberAPI) delete(c *gin.Context) {
})
}
type monitorForm struct {
ID uint64
Name string
Target string
Type uint8
Cover uint8
Notify string
//NotificationTag string
SkipServersRaw string
Duration uint64
MinLatency float32
MaxLatency float32
LatencyNotify string
EnableTriggerTask string
EnableShowInService string
FailTriggerTasksRaw string
RecoverTriggerTasksRaw string
}
func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
var mf monitorForm
var m model.Monitor
err := c.ShouldBindJSON(&mf)
if err == nil {
m.Name = mf.Name
m.Target = strings.TrimSpace(mf.Target)
m.Type = mf.Type
m.ID = mf.ID
m.SkipServersRaw = mf.SkipServersRaw
m.Cover = mf.Cover
m.Notify = mf.Notify == "on"
//m.NotificationTag = mf.NotificationTag
m.Duration = mf.Duration
m.LatencyNotify = mf.LatencyNotify == "on"
m.MinLatency = mf.MinLatency
m.MaxLatency = mf.MaxLatency
m.EnableShowInService = mf.EnableShowInService == "on"
m.EnableTriggerTask = mf.EnableTriggerTask == "on"
m.RecoverTriggerTasksRaw = mf.RecoverTriggerTasksRaw
m.FailTriggerTasksRaw = mf.FailTriggerTasksRaw
err = m.InitSkipServers()
}
if err == nil {
// 保证NotificationTag不为空
//if m.NotificationTag == "" {
// m.NotificationTag = "default"
//}
err = utils.Json.Unmarshal([]byte(mf.FailTriggerTasksRaw), &m.FailTriggerTasks)
}
if err == nil {
err = utils.Json.Unmarshal([]byte(mf.RecoverTriggerTasksRaw), &m.RecoverTriggerTasks)
}
if err == nil {
if m.ID == 0 {
err = singleton.DB.Create(&m).Error
} else {
err = singleton.DB.Save(&m).Error
}
}
if err == nil {
if m.Cover == 0 {
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ? and server_id in (?)", m.ID, strings.Split(m.SkipServersRaw[1:len(m.SkipServersRaw)-1], ",")).Error
} else {
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ? and server_id not in (?)", m.ID, strings.Split(m.SkipServersRaw[1:len(m.SkipServersRaw)-1], ",")).Error
}
}
if err == nil {
err = singleton.ServiceSentinelShared.OnMonitorUpdate(m)
}
if err != nil {
c.JSON(http.StatusOK, model.Response{
Code: http.StatusBadRequest,
Message: fmt.Sprintf("请求错误:%s", err),
})
return
}
c.JSON(http.StatusOK, model.Response{
Code: http.StatusOK,
})
}
type cronForm struct {
ID uint64
TaskType uint8 // 0:计划任务 1:触发任务

View File

@@ -21,8 +21,6 @@ func (mp *memberPage) serve() {
// // Btn: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
// Redirect: "/login",
// }))
mr.GET("/server", mp.server)
mr.GET("/monitor", mp.monitor)
mr.GET("/cron", mp.cron)
mr.GET("/notification", mp.notification)
mr.GET("/ddns", mp.ddns)
@@ -40,22 +38,6 @@ func (mp *memberPage) api(c *gin.Context) {
})
}
func (mp *memberPage) server(c *gin.Context) {
singleton.SortedServerLock.RLock()
defer singleton.SortedServerLock.RUnlock()
c.HTML(http.StatusOK, "dashboard-", gin.H{
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServersManagement"}),
"Servers": singleton.SortedServerList,
})
}
func (mp *memberPage) monitor(c *gin.Context) {
c.HTML(http.StatusOK, "dashboard-", gin.H{
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesManagement"}),
"Monitors": singleton.ServiceSentinelShared.Monitors(),
})
}
func (mp *memberPage) cron(c *gin.Context) {
var crons []model.Cron
singleton.DB.Find(&crons)

View File

@@ -0,0 +1,173 @@
package controller
import (
"fmt"
"strconv"
"strings"
"github.com/gin-gonic/gin"
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/service/singleton"
"gorm.io/gorm"
)
// List monitor
// @Summary List monitor
// @Security BearerAuth
// @Schemes
// @Description List monitor
// @Tags auth required
// @Produce json
// @Success 200 {object} model.CommonResponse[[]model.Monitor]
// @Router /monitor [get]
func listMonitor(c *gin.Context) ([]*model.Monitor, error) {
return singleton.ServiceSentinelShared.Monitors(), nil
}
// Create monitor
// @Summary Create monitor
// @Security BearerAuth
// @Schemes
// @Description Create monitor
// @Tags auth required
// @Accept json
// @param request body model.MonitorForm true "Monitor Request"
// @Produce json
// @Success 200 {object} model.CommonResponse[uint64]
// @Router /monitor [post]
func createMonitor(c *gin.Context) (uint64, error) {
var mf model.MonitorForm
if err := c.ShouldBindJSON(&mf); err != nil {
return 0, err
}
var m model.Monitor
m.Name = mf.Name
m.Target = strings.TrimSpace(mf.Target)
m.Type = mf.Type
m.SkipServers = mf.SkipServers
m.Cover = mf.Cover
m.Notify = mf.Notify
m.NotificationGroupID = mf.NotificationGroupID
m.Duration = mf.Duration
m.LatencyNotify = mf.LatencyNotify
m.MinLatency = mf.MinLatency
m.MaxLatency = mf.MaxLatency
m.EnableShowInService = mf.EnableShowInService
m.EnableTriggerTask = mf.EnableTriggerTask
m.RecoverTriggerTasks = mf.RecoverTriggerTasks
m.FailTriggerTasks = mf.FailTriggerTasks
if err := singleton.DB.Create(&m).Error; err != nil {
return 0, err
}
var skipServers []uint64
for k := range m.SkipServers {
skipServers = append(skipServers, k)
}
var err error
if m.Cover == 0 {
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ? and server_id in (?)", m.ID, skipServers).Error
} else {
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ? and server_id not in (?)", m.ID, skipServers).Error
}
if err != nil {
return 0, err
}
return m.ID, singleton.ServiceSentinelShared.OnMonitorUpdate(m)
}
// Update monitor
// @Summary Update monitor
// @Security BearerAuth
// @Schemes
// @Description Update monitor
// @Tags auth required
// @Accept json
// @param id path uint true "Monitor ID"
// @param request body model.MonitorForm true "Monitor Request"
// @Produce json
// @Success 200 {object} model.CommonResponse[any]
// @Router /monitor/{id} [patch]
func updateMonitor(c *gin.Context) (any, error) {
strID := c.Param("id")
id, err := strconv.ParseUint(strID, 10, 64)
if err != nil {
return nil, err
}
var mf model.MonitorForm
if err := c.ShouldBindJSON(&mf); err != nil {
return nil, err
}
var m model.Monitor
if err := singleton.DB.First(&m, id).Error; err != nil {
return nil, fmt.Errorf("monitor id %d does not exist", id)
}
m.Name = mf.Name
m.Target = strings.TrimSpace(mf.Target)
m.Type = mf.Type
m.SkipServers = mf.SkipServers
m.Cover = mf.Cover
m.Notify = mf.Notify
m.NotificationGroupID = mf.NotificationGroupID
m.Duration = mf.Duration
m.LatencyNotify = mf.LatencyNotify
m.MinLatency = mf.MinLatency
m.MaxLatency = mf.MaxLatency
m.EnableShowInService = mf.EnableShowInService
m.EnableTriggerTask = mf.EnableTriggerTask
m.RecoverTriggerTasks = mf.RecoverTriggerTasks
m.FailTriggerTasks = mf.FailTriggerTasks
if err := singleton.DB.Save(&m).Error; err != nil {
return nil, err
}
var skipServers []uint64
for k := range m.SkipServers {
skipServers = append(skipServers, k)
}
if m.Cover == 0 {
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ? and server_id in (?)", m.ID, skipServers).Error
} else {
err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ? and server_id not in (?)", m.ID, skipServers).Error
}
if err != nil {
return nil, err
}
return nil, singleton.ServiceSentinelShared.OnMonitorUpdate(m)
}
// Batch delete monitor
// @Summary Batch delete monitor
// @Security BearerAuth
// @Schemes
// @Description Batch delete monitor
// @Tags auth required
// @Accept json
// @param request body []uint true "id list"
// @Produce json
// @Success 200 {object} model.CommonResponse[any]
// @Router /batch-delete/monitor [post]
func batchDeleteMonitor(c *gin.Context) (any, error) {
var ids []uint64
if err := c.ShouldBindJSON(&ids); err != nil {
return nil, err
}
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
if err := tx.Unscoped().Delete(&model.Monitor{}, "id in (?)", ids).Error; err != nil {
return err
}
return tx.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id in (?)", ids).Error
})
if err != nil {
return nil, err
}
singleton.ServiceSentinelShared.OnMonitorDelete(ids)
return nil, nil
}

View File

@@ -20,12 +20,10 @@ import (
// @Produce json
// @Success 200 {object} model.CommonResponse[any]
// @Router /server [get]
func listServer(c *gin.Context) ([]model.Server, error) {
var servers []model.Server
if err := singleton.DB.Find(&servers).Error; err != nil {
return nil, newGormError("%v", err)
}
return servers, nil
func listServer(c *gin.Context) ([]*model.Server, error) {
singleton.SortedServerLock.RLock()
defer singleton.SortedServerLock.RUnlock()
return singleton.SortedServerList, nil
}
// Edit server