diff --git a/backend/app/api/v1/host_tool.go b/backend/app/api/v1/host_tool.go index 6e55b70e2..d7bed8048 100644 --- a/backend/app/api/v1/host_tool.go +++ b/backend/app/api/v1/host_tool.go @@ -189,6 +189,16 @@ func (b *BaseApi) GetProcess(c *gin.Context) { helper.SuccessWithData(c, configs) } +// @Tags Host tool +// @Summary Load Supervisor process status +// @Description 获取 Supervisor 进程状态 +// @Success 200 {array} response.ProcessStatus +// @Security ApiKeyAuth +// @Router /host/tool/supervisor/process/load [post] +func (b *BaseApi) LoadProcessStatus(c *gin.Context) { + helper.SuccessWithData(c, hostToolService.LoadProcessStatus()) +} + // @Tags Host tool // @Summary Get Supervisor process config // @Description 操作 Supervisor 进程文件 diff --git a/backend/app/service/host_tool.go b/backend/app/service/host_tool.go index 0b8e743e0..1ed671ed9 100644 --- a/backend/app/service/host_tool.go +++ b/backend/app/service/host_tool.go @@ -3,6 +3,14 @@ package service import ( "bytes" "fmt" + "os/exec" + "os/user" + "path" + "strconv" + "strings" + "sync" + "time" + "github.com/1Panel-dev/1Panel/backend/app/dto/request" "github.com/1Panel-dev/1Panel/backend/app/dto/response" "github.com/1Panel-dev/1Panel/backend/buserr" @@ -14,11 +22,6 @@ import ( "github.com/1Panel-dev/1Panel/backend/utils/systemctl" "github.com/pkg/errors" "gopkg.in/ini.v1" - "os/exec" - "os/user" - "path" - "strconv" - "strings" ) type HostToolService struct{} @@ -31,6 +34,7 @@ type IHostToolService interface { GetToolLog(req request.HostToolLogReq) (string, error) OperateSupervisorProcess(req request.SupervisorProcessConfig) error GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error) + LoadProcessStatus() []response.ProcessStatus OperateSupervisorProcessFile(req request.SupervisorProcessFileReq) (string, error) } @@ -364,6 +368,57 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess return nil } +func (h *HostToolService) LoadProcessStatus() []response.ProcessStatus { + var datas []response.ProcessStatus + statuLines, err := cmd.Exec("supervisorctl status") + if err != nil { + return datas + } + lines := strings.Split(string(statuLines), "\n") + for _, line := range lines { + fields := strings.Fields(line) + if len(fields) > 1 { + datas = append(datas, response.ProcessStatus{Name: fields[0]}) + } + } + + var wg sync.WaitGroup + wg.Add(len(datas)) + for i := 0; i < len(datas); i++ { + go func(index int) { + for t := 0; t < 3; t++ { + status, err := cmd.ExecWithTimeOut(fmt.Sprintf("supervisorctl status %s", datas[index].Name), 3*time.Second) + if err != nil { + time.Sleep(2 * time.Second) + continue + } + fields := strings.Fields(status) + if len(fields) < 5 { + time.Sleep(2 * time.Second) + continue + } + datas[index].Name = fields[0] + datas[index].Status = fields[1] + if fields[1] != "RUNNING" { + datas[index].Msg = strings.Join(fields[2:], " ") + time.Sleep(1 * time.Second) + continue + } + datas[index].PID = strings.TrimSuffix(fields[3], ",") + datas[index].Uptime = fields[5] + break + } + if len(datas[index].Status) == 0 { + datas[index].Status = "FATAL" + datas[index].Msg = "Timeout for getting process status" + } + wg.Done() + }(i) + } + wg.Wait() + return datas +} + func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error) { var ( result []response.SupervisorProcessConfig @@ -400,7 +455,6 @@ func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorPro if numprocs, _ := section.GetKey("numprocs"); numprocs != nil { config.Numprocs = numprocs.Value() } - _ = getProcessStatus(&config) result = append(result, config) } } @@ -528,29 +582,3 @@ func getProcessName(name, numprocs string) []string { } return processNames } - -func getProcessStatus(config *response.SupervisorProcessConfig) error { - var ( - processNames = []string{"status"} - ) - processNames = append(processNames, getProcessName(config.Name, config.Numprocs)...) - output, _ := exec.Command("supervisorctl", processNames...).Output() - lines := strings.Split(string(output), "\n") - for _, line := range lines { - fields := strings.Fields(line) - if len(fields) >= 5 { - status := response.ProcessStatus{ - Name: fields[0], - Status: fields[1], - } - if fields[1] == "RUNNING" { - status.PID = strings.TrimSuffix(fields[3], ",") - status.Uptime = fields[5] - } else { - status.Msg = strings.Join(fields[2:], " ") - } - config.Status = append(config.Status, status) - } - } - return nil -} diff --git a/backend/router/ro_host.go b/backend/router/ro_host.go index 69b485f7f..bbc99629b 100644 --- a/backend/router/ro_host.go +++ b/backend/router/ro_host.go @@ -54,6 +54,7 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) { hostRouter.POST("/tool/operate", baseApi.OperateTool) hostRouter.POST("/tool/config", baseApi.OperateToolConfig) hostRouter.POST("/tool/log", baseApi.GetToolLog) + hostRouter.POST("/tool/supervisor/process/load", baseApi.LoadProcessStatus) hostRouter.POST("/tool/supervisor/process", baseApi.OperateProcess) hostRouter.GET("/tool/supervisor/process", baseApi.GetProcess) hostRouter.POST("/tool/supervisor/process/file", baseApi.GetProcessFile) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 53fbfa0f4..a768f3f84 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -6340,6 +6340,31 @@ const docTemplate = `{ } } }, + "/host/tool/supervisor/process/load": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取 Supervisor 进程状态", + "tags": [ + "Host tool" + ], + "summary": "Load Supervisor process status", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/response.ProcessStatus" + } + } + } + } + } + }, "/hosts": { "post": { "security": [ @@ -17024,6 +17049,26 @@ const docTemplate = `{ } } }, + "response.ProcessStatus": { + "type": "object", + "properties": { + "PID": { + "type": "string" + }, + "msg": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uptime": { + "type": "string" + } + } + }, "response.WebsiteAcmeAccountDTO": { "type": "object", "properties": { diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 3d49d92fc..bc851222b 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -6333,6 +6333,31 @@ } } }, + "/host/tool/supervisor/process/load": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取 Supervisor 进程状态", + "tags": [ + "Host tool" + ], + "summary": "Load Supervisor process status", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/response.ProcessStatus" + } + } + } + } + } + }, "/hosts": { "post": { "security": [ @@ -17017,6 +17042,26 @@ } } }, + "response.ProcessStatus": { + "type": "object", + "properties": { + "PID": { + "type": "string" + }, + "msg": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "uptime": { + "type": "string" + } + } + }, "response.WebsiteAcmeAccountDTO": { "type": "object", "properties": { diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 8182f10f1..4a09557bb 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -3714,6 +3714,19 @@ definitions: uploadMaxSize: type: string type: object + response.ProcessStatus: + properties: + PID: + type: string + msg: + type: string + name: + type: string + status: + type: string + uptime: + type: string + type: object response.WebsiteAcmeAccountDTO: properties: createdAt: @@ -7880,6 +7893,21 @@ paths: formatEN: '[operate] Supervisor Process Config file' formatZH: '[operate] Supervisor 进程文件 ' paramKeys: [] + /host/tool/supervisor/process/load: + post: + description: 获取 Supervisor 进程状态 + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/response.ProcessStatus' + type: array + security: + - ApiKeyAuth: [] + summary: Load Supervisor process status + tags: + - Host tool /hosts: post: consumes: diff --git a/frontend/src/api/modules/host-tool.ts b/frontend/src/api/modules/host-tool.ts index 6c2d69063..c8ddd3a62 100644 --- a/frontend/src/api/modules/host-tool.ts +++ b/frontend/src/api/modules/host-tool.ts @@ -29,6 +29,10 @@ export const OperateSupervisorProcess = (req: HostTool.ProcessReq) => { return http.post(`/hosts/tool/supervisor/process`, req, 100000); }; +export const LoadProcessStatus = () => { + return http.post>(`/hosts/tool/supervisor/process/load`, {}, 40000); +}; + export const GetSupervisorProcess = () => { return http.get(`/hosts/tool/supervisor/process`); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 1d4bb7b97..e05ff3af0 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1671,10 +1671,10 @@ const message = { config: 'Supervisor configuration', primaryConfig: 'Main configuration file location', notSupportCrl: 'The supervisorctl is not detected, please refer to the official document for installation', - user: 'start user', - command: 'start command', - dir: 'run directory', - numprocs: 'Number of processes', + user: 'User', + command: 'Command', + dir: 'Directory', + numprocs: 'Numprocs', initWarn: 'The initialization operation needs to modify the [include] files parameter of the configuration file, the directory where the modified service configuration file is located: 1panel installation directory/1panel/tools/supervisord/supervisor.d/', operatorHelper: 'Operation {1} will be performed on {0}, continue? ', diff --git a/frontend/src/views/host/tool/supervisor/file/index.vue b/frontend/src/views/host/tool/supervisor/file/index.vue index 844ce23af..f9351f902 100644 --- a/frontend/src/views/host/tool/supervisor/file/index.vue +++ b/frontend/src/views/host/tool/supervisor/file/index.vue @@ -73,6 +73,8 @@ const handleReady = (payload) => { }; let timer: NodeJS.Timer | null = null; +const em = defineEmits(['search']); + const getContent = () => { loading.value = true; OperateSupervisorProcessFile(req) @@ -114,8 +116,9 @@ const submit = () => { loading.value = true; OperateSupervisorProcessFile(updateReq) .then(() => { + em('search'); + open.value = false; MsgSuccess(i18n.global.t('commons.msg.updateSuccess')); - getContent(); }) .finally(() => { loading.value = false; diff --git a/frontend/src/views/host/tool/supervisor/index.vue b/frontend/src/views/host/tool/supervisor/index.vue index 87a8c5609..30f3540c3 100644 --- a/frontend/src/views/host/tool/supervisor/index.vue +++ b/frontend/src/views/host/tool/supervisor/index.vue @@ -20,28 +20,41 @@