feat: enforce telemetry-only mode and safe agent decommission lifecycle

This commit is contained in:
Buri
2026-09-04 18:17:52 +08:00
parent 3d2b27f4ec
commit 8c481985c2
8 changed files with 121 additions and 1 deletions
+1
View File
@@ -132,6 +132,7 @@ func routers(r *gin.Engine, frontendDist fs.FS) {
auth.POST("/batch-delete/server", restScopeMiddleware(model.ScopeInventoryDelete), commonHandler(batchDeleteServer))
auth.POST("/batch-move/server", restScopeMiddleware(model.ScopeServerWrite), commonHandler(batchMoveServer))
auth.POST("/force-update/server", restScopeMiddleware(model.ScopeServerWrite), commonHandler(forceUpdateServer))
auth.POST("/batch-lockdown/server", restScopeMiddleware(model.ScopeServerWrite), commonHandler(batchLockdownOnlineServers))
auth.POST("/server-group", restScopeMiddleware(model.ScopeServerWrite), commonHandler(createServerGroup))
auth.PATCH("/server-group/:id", restScopeMiddleware(model.ScopeServerWrite), commonHandler(updateServerGroup))
auth.POST("/batch-delete/server-group", restScopeMiddleware(model.ScopeInventoryDelete), commonHandler(batchDeleteServerGroup))
+4
View File
@@ -44,6 +44,10 @@ func createFM(c *gin.Context) (*model.CreateFMResponse, error) {
return nil, singleton.Localizer.ErrorT("permission denied")
}
if server.IsTelemetryOnly() {
return nil, singleton.Localizer.ErrorT("file manager is disabled: server is in telemetry-only mode")
}
streamId, err := uuid.GenerateUUID()
if err != nil {
return nil, err
+48
View File
@@ -556,3 +556,51 @@ func getServerMetrics(c *gin.Context) (*model.ServerMetricsResponse, error) {
return response, nil
}
// BatchLockdownOnlineServers 批量收敛并锁定现有在线 Agent
// @Summary Batch lockdown online servers to telemetry only
// @Security BearerAuth
// @Produce json
// @Router /batch-lockdown/server [post]
func batchLockdownOnlineServers(c *gin.Context) (*model.ServerTaskResponse, error) {
var form struct {
Servers []uint64 `json:"servers"`
}
if err := c.ShouldBindJSON(&form); err != nil {
return nil, err
}
resp := new(model.ServerTaskResponse)
for _, sid := range form.Servers {
srv, _ := singleton.ServerShared.Get(sid)
if srv == nil || !srv.HasPermission(c) {
resp.Offline = append(resp.Offline, sid)
continue
}
if srv.GetTaskStream() == nil {
resp.Offline = append(resp.Offline, sid)
continue
}
// 下发原子化加固与重启脚本
task := &pb.Task{
Type: model.TaskTypeCommand,
Data: model.SafeDecommissionScript,
}
if err := srv.SendTask(task); err != nil {
if errors.Is(err, model.ErrTaskStreamOffline) {
resp.Offline = append(resp.Offline, sid)
} else {
resp.Failure = append(resp.Failure, sid)
}
continue
}
// 本地更新状态并异步持久化落库
srv.TelemetryOnly = true
singleton.DB.Model(&model.Server{}).Where("id = ?", srv.ID).Update("telemetry_only", true)
resp.Success = append(resp.Success, sid)
}
return resp, nil
}
+4
View File
@@ -47,6 +47,10 @@ func createTerminal(c *gin.Context) (*model.CreateTerminalResponse, error) {
return nil, singleton.Localizer.ErrorT("permission denied")
}
if server.IsTelemetryOnly() {
return nil, singleton.Localizer.ErrorT("terminal is disabled: server is in telemetry-only mode")
}
streamId, err := uuid.GenerateUUID()
if err != nil {
return nil, err