feat(cluster): add reload and restart for nginx

This commit is contained in:
Jacky 2025-04-05 15:37:47 +08:00
parent c086455772
commit 2d437ff0cc
No known key found for this signature in database
GPG key ID: 215C21B10DF38B4D
24 changed files with 2897 additions and 1239 deletions

View file

@ -1,6 +1,8 @@
package cluster
import (
"net/http"
"github.com/0xJacky/Nginx-UI/model"
"github.com/gin-gonic/gin"
"github.com/uozi-tech/cosy"
@ -17,6 +19,38 @@ func GetGroupList(c *gin.Context) {
}).PagingList()
}
func ReloadNginx(c *gin.Context) {
var json struct {
NodeIDs []uint64 `json:"node_ids" binding:"required"`
}
if !cosy.BindAndValid(c, &json) {
return
}
go syncReload(json.NodeIDs)
c.JSON(http.StatusOK, gin.H{
"message": "ok",
})
}
func RestartNginx(c *gin.Context) {
var json struct {
NodeIDs []uint64 `json:"node_ids" binding:"required"`
}
if !cosy.BindAndValid(c, &json) {
return
}
go syncRestart(json.NodeIDs)
c.JSON(http.StatusOK, gin.H{
"message": "ok",
})
}
func AddGroup(c *gin.Context) {
cosy.Core[model.EnvGroup](c).
SetValidRules(gin.H{

126
api/cluster/nginx.go Normal file
View file

@ -0,0 +1,126 @@
package cluster
import (
"net/http"
"runtime"
"sync"
"github.com/0xJacky/Nginx-UI/internal/notification"
"github.com/0xJacky/Nginx-UI/model"
"github.com/0xJacky/Nginx-UI/query"
"github.com/go-resty/resty/v2"
"github.com/uozi-tech/cosy/logger"
)
type syncResult struct {
Node string `json:"node"`
Resp string `json:"resp"`
}
// syncReload handle reload nginx on remote nodes
func syncReload(nodeIDs []uint64) {
if len(nodeIDs) == 0 {
return
}
e := query.Environment
nodes, err := e.Where(e.ID.In(nodeIDs...)).Find()
if err != nil {
logger.Error("Failed to get environment nodes:", err)
return
}
wg := &sync.WaitGroup{}
wg.Add(len(nodes))
for _, node := range nodes {
go func(node *model.Environment) {
defer func() {
if err := recover(); err != nil {
buf := make([]byte, 1024)
runtime.Stack(buf, false)
logger.Error(err)
}
}()
defer wg.Done()
client := resty.New()
client.SetBaseURL(node.URL)
resp, err := client.R().
SetHeader("X-Node-Secret", node.Token).
Post("/api/nginx/reload")
if err != nil {
notification.Error("Reload Remote Nginx Error", "", err.Error())
return
}
if resp.StatusCode() != http.StatusOK {
notification.Error("Reload Remote Nginx Error",
"Reload Nginx on %{node} failed, response: %{resp}", syncResult{
Node: node.Name,
Resp: resp.String(),
})
return
}
notification.Success("Reload Remote Nginx Success",
"Reload Nginx on %{node} successfully", syncResult{
Node: node.Name,
})
}(node)
}
wg.Wait()
}
// syncRestart handle restart nginx on remote nodes
func syncRestart(nodeIDs []uint64) {
if len(nodeIDs) == 0 {
return
}
e := query.Environment
nodes, err := e.Where(e.ID.In(nodeIDs...)).Find()
if err != nil {
logger.Error("Failed to get environment nodes:", err)
return
}
wg := &sync.WaitGroup{}
wg.Add(len(nodes))
for _, node := range nodes {
go func(node *model.Environment) {
defer func() {
if err := recover(); err != nil {
buf := make([]byte, 1024)
runtime.Stack(buf, false)
logger.Error(err)
}
}()
defer wg.Done()
client := resty.New()
client.SetBaseURL(node.URL)
resp, err := client.R().
SetHeader("X-Node-Secret", node.Token).
Post("/api/nginx/restart")
if err != nil {
notification.Error("Restart Remote Nginx Error", "", err.Error())
return
}
if resp.StatusCode() != http.StatusOK {
notification.Error("Restart Remote Nginx Error",
"Restart Nginx on %{node} failed, response: %{resp}", syncResult{
Node: node.Name,
Resp: resp.String(),
})
return
}
notification.Success("Restart Remote Nginx Success",
"Restart Nginx on %{node} successfully", syncResult{
Node: node.Name,
})
}(node)
}
wg.Wait()
}

View file

@ -17,6 +17,9 @@ func InitRouter(r *gin.RouterGroup) {
// Node
r.GET("node", GetCurrentNode)
r.POST("environments/reload_nginx", ReloadNginx)
r.POST("environments/restart_nginx", RestartNginx)
r.GET("env_groups", GetGroupList)
r.GET("env_groups/:id", GetGroup)
r.POST("env_groups", AddGroup)