Skip to content

Commit

Permalink
feat: edit server config online (#980)
Browse files Browse the repository at this point in the history
* feat: edit server config online

* clean

* refactor

* generate template

* fix deadlocks

* fix
  • Loading branch information
uubulb authored Jan 31, 2025
1 parent 82d40d4 commit 7e8985a
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 86 deletions.
2 changes: 2 additions & 0 deletions cmd/dashboard/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ func routers(r *gin.Engine, frontendDist fs.FS) {

auth.GET("/server", listHandler(listServer))
auth.PATCH("/server/:id", commonHandler(updateServer))
auth.GET("/server/:id/config", commonHandler(getServerConfig))
auth.POST("/server/:id/config", commonHandler(setServerConfig))
auth.POST("/batch-delete/server", commonHandler(batchDeleteServer))
auth.POST("/force-update/server", commonHandler(forceUpdateServer))

Expand Down
97 changes: 97 additions & 0 deletions cmd/dashboard/controller/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package controller

import (
"strconv"
"time"

"github.com/gin-gonic/gin"
"github.com/jinzhu/copier"
Expand Down Expand Up @@ -213,3 +214,99 @@ func forceUpdateServer(c *gin.Context) (*model.ForceUpdateResponse, error) {

return forceUpdateResp, nil
}

// Get server config
// @Summary Get server config
// @Security BearerAuth
// @Schemes
// @Description Get server config
// @Tags auth required
// @Produce json
// @Success 200 {object} model.CommonResponse[string]
// @Router /server/{id}/config [get]
func getServerConfig(c *gin.Context) (string, error) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
return "", err
}

singleton.ServerLock.RLock()
s, ok := singleton.ServerList[id]
if !ok || s.TaskStream == nil {
singleton.ServerLock.RUnlock()
return "", nil
}
singleton.ServerLock.RUnlock()

if !s.HasPermission(c) {
return "", singleton.Localizer.ErrorT("permission denied")
}

if err := s.TaskStream.Send(&pb.Task{
Type: model.TaskTypeReportConfig,
}); err != nil {
return "", err
}

timeout := time.NewTimer(time.Second * 10)
select {
case <-timeout.C:
return "", singleton.Localizer.ErrorT("operation timeout")
case data := <-s.ConfigCache:
timeout.Stop()
switch data := data.(type) {
case string:
return data, nil
case error:
return "", singleton.Localizer.ErrorT("get server config failed: %v", data)
}
}

return "", singleton.Localizer.ErrorT("get server config failed")
}

// Set server config
// @Summary Set server config
// @Security BearerAuth
// @Schemes
// @Description Set server config
// @Tags auth required
// @Accept json
// @param request body string true "config"
// @Produce json
// @Success 200 {object} model.CommonResponse[any]
// @Router /server/{id}/config [post]
func setServerConfig(c *gin.Context) (any, error) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
return "", err
}

var configRaw string
if err := c.ShouldBindJSON(&configRaw); err != nil {
return nil, err
}

singleton.ServerLock.RLock()
s, ok := singleton.ServerList[id]
if !ok || s.TaskStream == nil {
singleton.ServerLock.RUnlock()
return "", nil
}
singleton.ServerLock.RUnlock()

if !s.HasPermission(c) {
return "", singleton.Localizer.ErrorT("permission denied")
}

if err := s.TaskStream.Send(&pb.Task{
Type: model.TaskTypeApplyConfig,
Data: configRaw,
}); err != nil {
return "", err
}

return nil, nil
}
10 changes: 9 additions & 1 deletion model/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,20 @@ type Server struct {
GeoIP *GeoIP `gorm:"-" json:"geoip,omitempty"`
LastActive time.Time `gorm:"-" json:"last_active,omitempty"`

TaskStream pb.NezhaService_RequestTaskServer `gorm:"-" json:"-"`
TaskStream pb.NezhaService_RequestTaskServer `gorm:"-" json:"-"`
ConfigCache chan any `gorm:"-" json:"-"`

PrevTransferInSnapshot int64 `gorm:"-" json:"-"` // 上次数据点时的入站使用量
PrevTransferOutSnapshot int64 `gorm:"-" json:"-"` // 上次数据点时的出站使用量
}

func InitServer(s *Server) {
s.Host = &Host{}
s.State = &HostState{}
s.GeoIP = &GeoIP{}
s.ConfigCache = make(chan any, 1)
}

func (s *Server) CopyFromRunningServer(old *Server) {
s.Host = old.Host
s.State = old.State
Expand Down
11 changes: 10 additions & 1 deletion model/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const (
TaskTypeNAT
TaskTypeReportHostInfoDeprecated
TaskTypeFM
TaskTypeReportConfig
TaskTypeApplyConfig
)

type TerminalTask struct {
Expand Down Expand Up @@ -127,5 +129,12 @@ func (m *Service) AfterFind(tx *gorm.DB) error {

// IsServiceSentinelNeeded 判断该任务类型是否需要进行服务监控 需要则返回true
func IsServiceSentinelNeeded(t uint64) bool {
return t != TaskTypeCommand && t != TaskTypeTerminalGRPC && t != TaskTypeUpgrade && t != TaskTypeKeepalive
switch t {
case TaskTypeCommand, TaskTypeTerminalGRPC, TaskTypeUpgrade,
TaskTypeKeepalive, TaskTypeNAT, TaskTypeFM,
TaskTypeReportConfig, TaskTypeApplyConfig:
return false
default:
return true
}
}
74 changes: 43 additions & 31 deletions pkg/i18n/template.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-12-31 21:25+0800\n"
"POT-Creation-Date: 2025-01-30 21:58+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand All @@ -25,28 +25,28 @@ msgstr ""
#: cmd/dashboard/controller/alertrule.go:108
#: cmd/dashboard/controller/alertrule.go:156
#: cmd/dashboard/controller/alertrule.go:176
#: cmd/dashboard/controller/controller.go:216
#: cmd/dashboard/controller/controller.go:226
#: cmd/dashboard/controller/cron.go:58 cmd/dashboard/controller/cron.go:124
#: cmd/dashboard/controller/cron.go:136 cmd/dashboard/controller/cron.go:195
#: cmd/dashboard/controller/cron.go:224 cmd/dashboard/controller/ddns.go:131
#: cmd/dashboard/controller/ddns.go:192 cmd/dashboard/controller/fm.go:43
#: cmd/dashboard/controller/nat.go:59 cmd/dashboard/controller/nat.go:110
#: cmd/dashboard/controller/nat.go:121 cmd/dashboard/controller/nat.go:160
#: cmd/dashboard/controller/nat.go:59 cmd/dashboard/controller/nat.go:111
#: cmd/dashboard/controller/nat.go:122 cmd/dashboard/controller/nat.go:162
#: cmd/dashboard/controller/notification.go:112
#: cmd/dashboard/controller/notification.go:166
#: cmd/dashboard/controller/notification_group.go:76
#: cmd/dashboard/controller/notification_group.go:152
#: cmd/dashboard/controller/notification_group.go:164
#: cmd/dashboard/controller/notification_group.go:233
#: cmd/dashboard/controller/server.go:65 cmd/dashboard/controller/server.go:77
#: cmd/dashboard/controller/server.go:128
#: cmd/dashboard/controller/server.go:192
#: cmd/dashboard/controller/server.go:66 cmd/dashboard/controller/server.go:78
#: cmd/dashboard/controller/server.go:137
#: cmd/dashboard/controller/server.go:201
#: cmd/dashboard/controller/server_group.go:75
#: cmd/dashboard/controller/server_group.go:150
#: cmd/dashboard/controller/server_group.go:229
#: cmd/dashboard/controller/service.go:273
#: cmd/dashboard/controller/service.go:344
#: cmd/dashboard/controller/service.go:371
#: cmd/dashboard/controller/service.go:271
#: cmd/dashboard/controller/service.go:342
#: cmd/dashboard/controller/service.go:369
#: cmd/dashboard/controller/terminal.go:41
msgid "permission denied"
msgstr ""
Expand All @@ -71,15 +71,15 @@ msgstr ""
msgid "need to configure at least a single rule"
msgstr ""

#: cmd/dashboard/controller/controller.go:210
#: cmd/dashboard/controller/oauth2.go:152
#: cmd/dashboard/controller/controller.go:220
#: cmd/dashboard/controller/oauth2.go:153
#: cmd/dashboard/controller/server_group.go:162
#: cmd/dashboard/controller/service.go:96 cmd/dashboard/controller/user.go:27
#: cmd/dashboard/controller/service.go:97 cmd/dashboard/controller/user.go:27
#: cmd/dashboard/controller/user.go:63
msgid "unauthorized"
msgstr ""

#: cmd/dashboard/controller/controller.go:233
#: cmd/dashboard/controller/controller.go:243
msgid "database error"
msgstr ""

Expand All @@ -100,7 +100,7 @@ msgstr ""
msgid "error parsing %s: %v"
msgstr ""

#: cmd/dashboard/controller/ddns.go:127 cmd/dashboard/controller/nat.go:117
#: cmd/dashboard/controller/ddns.go:127 cmd/dashboard/controller/nat.go:118
#, c-format
msgid "profile id %d does not exist"
msgstr ""
Expand Down Expand Up @@ -147,32 +147,44 @@ msgstr ""
msgid "code is required"
msgstr ""

#: cmd/dashboard/controller/oauth2.go:174
#: cmd/dashboard/controller/oauth2.go:175
msgid "oauth2 user not binded yet"
msgstr ""

#: cmd/dashboard/controller/oauth2.go:215
#: cmd/dashboard/controller/oauth2.go:221
#: cmd/dashboard/controller/oauth2.go:226
#: cmd/dashboard/controller/oauth2.go:217
#: cmd/dashboard/controller/oauth2.go:223
#: cmd/dashboard/controller/oauth2.go:228
msgid "invalid state key"
msgstr ""

#: cmd/dashboard/controller/server.go:73
#: cmd/dashboard/controller/server.go:74
#, c-format
msgid "server id %d does not exist"
msgstr ""

#: cmd/dashboard/controller/server.go:250
msgid "operation timeout"
msgstr ""

#: cmd/dashboard/controller/server.go:257
msgid "get server config failed: %v"
msgstr ""

#: cmd/dashboard/controller/server.go:261
msgid "get server config failed"
msgstr ""

#: cmd/dashboard/controller/server_group.go:92
#: cmd/dashboard/controller/server_group.go:172
msgid "have invalid server id"
msgstr ""

#: cmd/dashboard/controller/service.go:89
#: cmd/dashboard/controller/service.go:90
#: cmd/dashboard/controller/service.go:165
msgid "server not found"
msgstr ""

#: cmd/dashboard/controller/service.go:269
#: cmd/dashboard/controller/service.go:267
#, c-format
msgid "service id %d does not exist"
msgstr ""
Expand All @@ -185,19 +197,19 @@ msgstr ""
msgid "you don't have any oauth2 bindings"
msgstr ""

#: cmd/dashboard/controller/user.go:130
#: cmd/dashboard/controller/user.go:131
msgid "password length must be greater than 6"
msgstr ""

#: cmd/dashboard/controller/user.go:133
#: cmd/dashboard/controller/user.go:134
msgid "username can't be empty"
msgstr ""

#: cmd/dashboard/controller/user.go:136
#: cmd/dashboard/controller/user.go:137
msgid "invalid role"
msgstr ""

#: cmd/dashboard/controller/user.go:175
#: cmd/dashboard/controller/user.go:176
msgid "can't delete yourself"
msgstr ""

Expand All @@ -213,23 +225,23 @@ msgstr ""
msgid "timeout: agent connection not established"
msgstr ""

#: service/rpc/nezha.go:69
#: service/rpc/nezha.go:71
msgid "Scheduled Task Executed Successfully"
msgstr ""

#: service/rpc/nezha.go:73
#: service/rpc/nezha.go:75
msgid "Scheduled Task Executed Failed"
msgstr ""

#: service/rpc/nezha.go:245
#: service/rpc/nezha.go:274
msgid "IP Changed"
msgstr ""

#: service/singleton/alertsentinel.go:170
#: service/singleton/alertsentinel.go:169
msgid "Incident"
msgstr ""

#: service/singleton/alertsentinel.go:180
#: service/singleton/alertsentinel.go:179
msgid "Resolved"
msgstr ""

Expand Down
Binary file modified pkg/i18n/translations/en_US/LC_MESSAGES/nezha.mo
Binary file not shown.
Loading

0 comments on commit 7e8985a

Please sign in to comment.