diff --git a/Makefile b/Makefile index 2bcf237a2..441f164d8 100644 --- a/Makefile +++ b/Makefile @@ -29,10 +29,6 @@ build_backend_on_darwin: cd $(SERVER_PATH) \ && GOOS=linux GOARCH=amd64 $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN) -build_backend_on_archlinux: - cd $(SERVER_PATH) \ - && GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN) - build_all: build_frontend build_backend_on_linux build_on_local: clean_assets build_frontend build_backend_on_darwin upx_bin diff --git a/backend/app/api/v1/entry.go b/backend/app/api/v1/entry.go index ca02b8a9c..8dcd7db56 100644 --- a/backend/app/api/v1/entry.go +++ b/backend/app/api/v1/entry.go @@ -51,4 +51,6 @@ var ( runtimeService = service.NewRuntimeService() processService = service.NewIProcessService() + + hostToolService = service.NewIHostToolService() ) diff --git a/backend/app/api/v1/host_tool.go b/backend/app/api/v1/host_tool.go new file mode 100644 index 000000000..0c46850ac --- /dev/null +++ b/backend/app/api/v1/host_tool.go @@ -0,0 +1,174 @@ +package v1 + +import ( + "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" + "github.com/1Panel-dev/1Panel/backend/app/dto/request" + "github.com/1Panel-dev/1Panel/backend/constant" + "github.com/1Panel-dev/1Panel/backend/global" + "github.com/gin-gonic/gin" +) + +// @Tags Host tool +// @Summary Get tool +// @Description 获取主机工具状态 +// @Accept json +// @Param request body request.HostToolReq true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /host/tool [post] +func (b *BaseApi) GetToolStatus(c *gin.Context) { + var req request.HostToolReq + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + config, err := hostToolService.GetToolStatus(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, config) +} + +// @Tags Host tool +// @Summary Create Host tool Config +// @Description 创建主机工具配置 +// @Accept json +// @Param request body request.HostToolCreate true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /host/tool/create [post] +// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建 [type] 配置","formatEN":"create [type] config"} +func (b *BaseApi) InitToolConfig(c *gin.Context) { + var req request.HostToolCreate + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + if err := hostToolService.CreateToolConfig(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithOutData(c) +} + +// @Tags Host tool +// @Summary Operate tool +// @Description 操作主机工具 +// @Accept json +// @Param request body request.HostToolReq true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /host/tool/operate [post] +// @x-panel-log {"bodyKeys":["operate","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] [type] ","formatEN":"[operate] [type]"} +func (b *BaseApi) OperateTool(c *gin.Context) { + var req request.HostToolReq + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + err := hostToolService.OperateTool(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithOutData(c) +} + +// @Tags Host tool +// @Summary Get tool config +// @Description 操作主机工具配置文件 +// @Accept json +// @Param request body request.HostToolConfig true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /host/tool/config [post] +// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] 主机工具配置文件 ","formatEN":"[operate] tool config"} +func (b *BaseApi) OperateToolConfig(c *gin.Context) { + var req request.HostToolConfig + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + config, err := hostToolService.OperateToolConfig(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, config) +} + +// @Tags Host tool +// @Summary Get tool +// @Description 获取主机工具日志 +// @Accept json +// @Param request body request.HostToolLogReq true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /host/tool/log [post] +func (b *BaseApi) GetToolLog(c *gin.Context) { + var req request.HostToolLogReq + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + logContent, err := hostToolService.GetToolLog(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, logContent) +} + +// @Tags Host tool +// @Summary Create Supervisor process +// @Description 操作守护进程 +// @Accept json +// @Param request body request.SupervisorProcessConfig true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /host/tool/supervisor/process [post] +// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operate] 守护进程 ","formatEN":"[operate] process"} +func (b *BaseApi) OperateProcess(c *gin.Context) { + var req request.SupervisorProcessConfig + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + err := hostToolService.OperateSupervisorProcess(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithOutData(c) +} diff --git a/backend/app/dto/request/host_tool.go b/backend/app/dto/request/host_tool.go new file mode 100644 index 000000000..5f76db256 --- /dev/null +++ b/backend/app/dto/request/host_tool.go @@ -0,0 +1,34 @@ +package request + +type HostToolReq struct { + Type string `json:"type" validate:"required,oneof=supervisord"` + Operate string `json:"operate" validate:"oneof=status restart start stop"` +} + +type HostToolCreate struct { + Type string `json:"type" validate:"required"` + SupervisorConfig +} + +type SupervisorConfig struct { + ConfigPath string `json:"configPath"` +} + +type HostToolLogReq struct { + Type string `json:"type" validate:"required,oneof=supervisord"` +} + +type HostToolConfig struct { + Type string `json:"type" validate:"required,oneof=supervisord"` + Operate string `json:"operate" validate:"oneof=get set"` + Content string `json:"content"` +} + +type SupervisorProcessConfig struct { + Name string `json:"name"` + Operate string `json:"operate"` + Command string `json:"command"` + User string `json:"user"` + Dir string `json:"dir"` + Numprocs string `json:"numprocs"` +} diff --git a/backend/app/dto/response/host_tool.go b/backend/app/dto/response/host_tool.go new file mode 100644 index 000000000..21db3a53a --- /dev/null +++ b/backend/app/dto/response/host_tool.go @@ -0,0 +1,22 @@ +package response + +type HostToolRes struct { + Type string `json:"type"` + Config interface{} `json:"config"` +} + +type Supervisor struct { + ConfigPath string `json:"configPath"` + IncludeDir string `json:"includeDir"` + LogPath string `json:"logPath"` + IsExist bool `json:"isExist"` + Init bool `json:"init"` + Msg string `json:"msg"` + Version string `json:"version"` + Status string `json:"status"` + CtlExist bool `json:"ctlExist"` +} + +type HostToolConfig struct { + Content string `json:"content"` +} diff --git a/backend/app/service/host_tool.go b/backend/app/service/host_tool.go new file mode 100644 index 000000000..70985010f --- /dev/null +++ b/backend/app/service/host_tool.go @@ -0,0 +1,259 @@ +package service + +import ( + "bytes" + "fmt" + "github.com/1Panel-dev/1Panel/backend/app/dto/request" + "github.com/1Panel-dev/1Panel/backend/app/dto/response" + "github.com/1Panel-dev/1Panel/backend/constant" + "github.com/1Panel-dev/1Panel/backend/global" + "github.com/1Panel-dev/1Panel/backend/utils/cmd" + "github.com/1Panel-dev/1Panel/backend/utils/files" + "github.com/1Panel-dev/1Panel/backend/utils/ini_conf" + "github.com/1Panel-dev/1Panel/backend/utils/systemctl" + "github.com/pkg/errors" + "gopkg.in/ini.v1" + "os/exec" + "path" + "strings" +) + +type HostToolService struct{} + +type IHostToolService interface { + GetToolStatus(req request.HostToolReq) (*response.HostToolRes, error) + CreateToolConfig(req request.HostToolCreate) error + OperateTool(req request.HostToolReq) error + OperateToolConfig(req request.HostToolConfig) (*response.HostToolConfig, error) + GetToolLog(req request.HostToolLogReq) (string, error) + OperateSupervisorProcess(req request.SupervisorProcessConfig) error +} + +func NewIHostToolService() IHostToolService { + return &HostToolService{} +} + +func (h *HostToolService) GetToolStatus(req request.HostToolReq) (*response.HostToolRes, error) { + res := &response.HostToolRes{} + res.Type = req.Type + switch req.Type { + case constant.Supervisord: + exist, err := systemctl.IsExist(constant.Supervisord) + if err != nil { + return nil, err + } + supervisorConfig := &response.Supervisor{} + if !exist { + supervisorConfig.IsExist = false + return res, nil + } + supervisorConfig.IsExist = true + + versionRes, _ := cmd.Exec("supervisord -v") + supervisorConfig.Version = strings.TrimSuffix(versionRes, "\n") + _, ctlRrr := exec.LookPath("supervisorctl") + supervisorConfig.CtlExist = ctlRrr == nil + + active, err := systemctl.IsActive(constant.Supervisord) + if err != nil { + supervisorConfig.Status = "unhealthy" + supervisorConfig.Msg = err.Error() + res.Config = supervisorConfig + return res, nil + } + if active { + supervisorConfig.Status = "running" + } else { + supervisorConfig.Status = "stopped" + } + + pathSet, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorConfigPath)) + if pathSet.ID != 0 || pathSet.Value != "" { + supervisorConfig.ConfigPath = pathSet.Value + res.Config = supervisorConfig + return res, nil + } + supervisorConfig.Init = true + + servicePath := "/usr/lib/systemd/system/supervisord.service" + fileOp := files.NewFileOp() + if !fileOp.Stat(servicePath) { + servicePath = "/lib/systemd/system/supervisord.service" + } + if fileOp.Stat(servicePath) { + startCmd, _ := ini_conf.GetIniValue(servicePath, "Service", "ExecStart") + if startCmd != "" { + args := strings.Fields(startCmd) + cIndex := -1 + for i, arg := range args { + if arg == "-c" { + cIndex = i + break + } + } + if cIndex != -1 && cIndex+1 < len(args) { + supervisorConfig.ConfigPath = args[cIndex+1] + } + } + } else { + configPath := "/etc/supervisord.conf" + if !fileOp.Stat(configPath) { + configPath = "/etc/supervisor/supervisord.conf" + if !fileOp.Stat("configPath") { + return nil, errors.New("ErrConfigNotFound") + } + } + } + + res.Config = supervisorConfig + } + return res, nil +} + +func (h *HostToolService) CreateToolConfig(req request.HostToolCreate) error { + switch req.Type { + case constant.Supervisord: + fileOp := files.NewFileOp() + if !fileOp.Stat(req.ConfigPath) { + return errors.New("ErrConfigNotFound") + } + cfg, err := ini.Load(req.ConfigPath) + if err != nil { + return err + } + service, err := cfg.GetSection("include") + if err != nil { + return err + } + targetKey, err := service.GetKey("files") + if err != nil { + return err + } + if targetKey != nil { + _, err = service.NewKey(";files", targetKey.Value()) + if err != nil { + return err + } + } + supervisorDir := path.Join(global.CONF.System.BaseDir, "1panel", "tools", "supervisord") + includeDir := path.Join(supervisorDir, "supervisor.d") + if !fileOp.Stat(includeDir) { + if err = fileOp.CreateDir(includeDir, 0755); err != nil { + return err + } + } + logDir := path.Join(supervisorDir, "log") + if !fileOp.Stat(logDir) { + if err = fileOp.CreateDir(logDir, 0755); err != nil { + return err + } + } + includePath := path.Join(includeDir, "*.ini") + targetKey.SetValue(includePath) + if err = cfg.SaveTo(req.ConfigPath); err != nil { + return err + } + if err = settingRepo.Create(constant.SupervisorConfigPath, req.ConfigPath); err != nil { + return err + } + go func() { + if err = systemctl.Restart(constant.Supervisord); err != nil { + global.LOG.Errorf("[init] restart supervisord failed err %s", err.Error()) + } + }() + } + return nil +} + +func (h *HostToolService) OperateTool(req request.HostToolReq) error { + return systemctl.Operate(req.Operate, req.Type) +} + +func (h *HostToolService) OperateToolConfig(req request.HostToolConfig) (*response.HostToolConfig, error) { + fileOp := files.NewFileOp() + res := &response.HostToolConfig{} + configPath := "" + switch req.Type { + case constant.Supervisord: + pathSet, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorConfigPath)) + if pathSet.ID != 0 || pathSet.Value != "" { + configPath = pathSet.Value + } + } + configPath = "/etc/supervisord.conf" + switch req.Operate { + case "get": + content, err := fileOp.GetContent(configPath) + if err != nil { + return nil, err + } + res.Content = string(content) + case "set": + file, err := fileOp.OpenFile(configPath) + if err != nil { + return nil, err + } + oldContent, err := fileOp.GetContent(configPath) + if err != nil { + return nil, err + } + fileInfo, err := file.Stat() + if err != nil { + return nil, err + } + if err = fileOp.WriteFile(configPath, strings.NewReader(req.Content), fileInfo.Mode()); err != nil { + return nil, err + } + if err = systemctl.Restart(req.Type); err != nil { + _ = fileOp.WriteFile(configPath, bytes.NewReader(oldContent), fileInfo.Mode()) + return nil, err + } + } + + return res, nil +} + +func (h *HostToolService) GetToolLog(req request.HostToolLogReq) (string, error) { + fileOp := files.NewFileOp() + logfilePath := "" + switch req.Type { + case constant.Supervisord: + configPath := "/etc/supervisord.conf" + pathSet, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorConfigPath)) + if pathSet.ID != 0 || pathSet.Value != "" { + configPath = pathSet.Value + } + logfilePath, _ = ini_conf.GetIniValue(configPath, "supervisord", "logfile") + } + oldContent, err := fileOp.GetContent(logfilePath) + if err != nil { + return "", err + } + return string(oldContent), nil +} + +func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcessConfig) error { + configFile := ini.Empty() + supervisordDir := path.Join(global.CONF.System.BaseDir, "1panel", "tools", "supervisord") + logDir := path.Join(supervisordDir, "log") + includeDir := path.Join(supervisordDir, "supervisor.d") + + section, err := configFile.NewSection(fmt.Sprintf("program:%s", req.Name)) + if err != nil { + return err + } + _, _ = section.NewKey("command", req.Command) + _, _ = section.NewKey("directory", req.Dir) + _, _ = section.NewKey("autorestart", "true") + _, _ = section.NewKey("startsecs", "3") + _, _ = section.NewKey("stdout_logfile", path.Join(logDir, fmt.Sprintf("%s.out.log", req.Name))) + _, _ = section.NewKey("stderr_logfile", path.Join(logDir, fmt.Sprintf("%s.err.log", req.Name))) + _, _ = section.NewKey("stdout_logfile_maxbytes", "2MB") + _, _ = section.NewKey("stderr_logfile_maxbytes", "2MB") + _, _ = section.NewKey("user", req.User) + _, _ = section.NewKey("priority", "999") + _, _ = section.NewKey("numprocs", req.Numprocs) + _, _ = section.NewKey("process_name", "%(program_name)s_%(process_num)02d") + + return configFile.SaveTo(path.Join(includeDir, fmt.Sprintf("%s.ini", req.Name))) +} diff --git a/backend/constant/host_tool.go b/backend/constant/host_tool.go new file mode 100644 index 000000000..bfaff46c8 --- /dev/null +++ b/backend/constant/host_tool.go @@ -0,0 +1,6 @@ +package constant + +const ( + Supervisord = "supervisord" + SupervisorConfigPath = "SupervisorConfigPath" +) diff --git a/backend/i18n/lang/en.yaml b/backend/i18n/lang/en.yaml index 5c3dcc174..ad606c86b 100644 --- a/backend/i18n/lang/en.yaml +++ b/backend/i18n/lang/en.yaml @@ -97,5 +97,7 @@ ErrDelWithWebsite: "The operating environment has been associated with a website #setting ErrBackupInUsed: "The backup account is already being used in a cronjob and cannot be deleted." +ErrOSSConn: "Unable to successfully request the latest version. Please check if the server can connect to the external network environment." -ErrOSSConn: "Unable to successfully request the latest version. Please check if the server can connect to the external network environment." \ No newline at end of file +#tool +ErrConfigNotFound: "Configuration file does not exist" \ No newline at end of file diff --git a/backend/i18n/lang/zh-Hant.yaml b/backend/i18n/lang/zh-Hant.yaml index 8587ea2bb..9f23a10f6 100644 --- a/backend/i18n/lang/zh-Hant.yaml +++ b/backend/i18n/lang/zh-Hant.yaml @@ -97,5 +97,7 @@ ErrDelWithWebsite: "運行環境已經關聯網站,無法刪除" #setting ErrBackupInUsed: "該備份帳號已在計劃任務中使用,無法刪除" - ErrOSSConn: "無法成功請求最新版本,請檢查伺服器是否能夠連接到外部網絡環境。" + +#tool +ErrConfigNotFound: "配置文件不存在" diff --git a/backend/i18n/lang/zh.yaml b/backend/i18n/lang/zh.yaml index 0807a525b..90a5c49e1 100644 --- a/backend/i18n/lang/zh.yaml +++ b/backend/i18n/lang/zh.yaml @@ -97,5 +97,7 @@ ErrDelWithWebsite: "运行环境已经关联网站,无法删除" #setting ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除" - ErrOSSConn: "无法成功请求最新版本,请检查服务器是否能够连接到外部网络环境。" + +#tool +ErrConfigNotFound: "配置文件不存在" diff --git a/backend/router/ro_host.go b/backend/router/ro_host.go index 3c54864d9..fec9bc3db 100644 --- a/backend/router/ro_host.go +++ b/backend/router/ro_host.go @@ -47,5 +47,12 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) { hostRouter.POST("/command/del", baseApi.DeleteCommand) hostRouter.POST("/command/search", baseApi.SearchCommand) hostRouter.POST("/command/update", baseApi.UpdateCommand) + + hostRouter.POST("/tool", baseApi.GetToolStatus) + hostRouter.POST("/tool/init", baseApi.InitToolConfig) + hostRouter.POST("/tool/operate", baseApi.OperateTool) + hostRouter.POST("/tool/config", baseApi.OperateToolConfig) + hostRouter.POST("/tool/log", baseApi.GetToolLog) + hostRouter.POST("/tool/supervisor/process", baseApi.OperateProcess) } } diff --git a/backend/utils/ini_conf/ini.go b/backend/utils/ini_conf/ini.go new file mode 100644 index 000000000..b2ee144a3 --- /dev/null +++ b/backend/utils/ini_conf/ini.go @@ -0,0 +1,36 @@ +package ini_conf + +import "gopkg.in/ini.v1" + +func GetIniValue(filePath, Group, Key string) (string, error) { + cfg, err := ini.Load(filePath) + if err != nil { + return "", err + } + service, err := cfg.GetSection(Group) + if err != nil { + return "", err + } + startKey, err := service.GetKey(Key) + if err != nil { + return "", err + } + return startKey.Value(), nil +} + +func SetIniValue(filePath, Group, Key, value string) error { + cfg, err := ini.Load(filePath) + if err != nil { + return err + } + service, err := cfg.GetSection(Group) + if err != nil { + return err + } + targetKey := service.Key(Key) + if err != nil { + return err + } + targetKey.SetValue(value) + return cfg.SaveTo(filePath) +} diff --git a/backend/utils/systemctl/systemctl.go b/backend/utils/systemctl/systemctl.go new file mode 100644 index 000000000..27ff4be6d --- /dev/null +++ b/backend/utils/systemctl/systemctl.go @@ -0,0 +1,62 @@ +package systemctl + +import ( + "fmt" + "github.com/pkg/errors" + "os/exec" + "strings" +) + +func RunSystemCtl(args ...string) (string, error) { + cmd := exec.Command("systemctl", args...) + output, err := cmd.CombinedOutput() + if err != nil { + return string(output), fmt.Errorf("failed to run command: %w", err) + } + return string(output), nil +} + +func IsActive(serviceName string) (bool, error) { + out, err := RunSystemCtl("is-active", serviceName) + if err != nil { + return false, err + } + return out == "active\n", nil +} + +func IsExist(serviceName string) (bool, error) { + out, err := RunSystemCtl("list-unit-files") + if err != nil { + return false, err + } + return strings.Contains(out, serviceName+".service"), nil +} + +func handlerErr(out string, err error) error { + if err != nil { + if out != "" { + return errors.New(out) + } + return err + } + return nil +} + +func Restart(serviceName string) error { + out, err := RunSystemCtl("restart", serviceName) + return handlerErr(out, err) +} +func Start(serviceName string) error { + out, err := RunSystemCtl("start", serviceName) + return handlerErr(out, err) +} + +func Stop(serviceName string) error { + out, err := RunSystemCtl("stop", serviceName) + return handlerErr(out, err) +} + +func Operate(operate, serviceName string) error { + out, err := RunSystemCtl(operate, serviceName) + return handlerErr(out, err) +} diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index dbb857c23..022f4b884 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -3910,6 +3910,21 @@ const docTemplate = `{ } } }, + "/databases/load/:from": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "从服务器获取", + "tags": [ + "Database Mysql" + ], + "summary": "Load mysql database from remote", + "responses": {} + } + }, "/databases/options": { "get": { "security": [ @@ -4274,6 +4289,28 @@ const docTemplate = `{ } } }, + "/databases/remote/:name": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取远程数据库", + "tags": [ + "Database" + ], + "summary": "Get remote databases", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dto.RemoteDBInfo" + } + } + } + } + }, "/databases/remote/del": { "post": { "security": [ @@ -4332,7 +4369,7 @@ const docTemplate = `{ "ApiKeyAuth": [] } ], - "description": "获取快速命令列表", + "description": "获取远程数据库列表", "tags": [ "Database" ], @@ -5923,6 +5960,241 @@ const docTemplate = `{ } } }, + "/host/tool": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取主机工具状态", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Get tool", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.HostToolReq" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/host/tool/config": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "操作主机工具配置文件", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Get tool config", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.HostToolConfig" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "operate" + ], + "formatEN": "[operate] tool config", + "formatZH": "[operate] 主机工具配置文件 ", + "paramKeys": [] + } + } + }, + "/host/tool/create": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "创建主机工具配置", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Create Host tool Config", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.HostToolCreate" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "type" + ], + "formatEN": "create [type] config", + "formatZH": "创建 [type] 配置", + "paramKeys": [] + } + } + }, + "/host/tool/log": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取主机工具日志", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Get tool", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.HostToolLogReq" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/host/tool/operate": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "操作主机工具", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Operate tool", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.HostToolReq" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "operate", + "type" + ], + "formatEN": "[operate] [type]", + "formatZH": "[operate] [type] ", + "paramKeys": [] + } + } + }, + "/host/tool/supervisor/process": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "操作守护进程", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Create Supervisor process", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SupervisorProcessConfig" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "operate" + ], + "formatEN": "[operate] process", + "formatZH": "[operate] 守护进程 ", + "paramKeys": [] + } + } + }, "/hosts": { "post": { "security": [ @@ -13317,6 +13589,41 @@ const docTemplate = `{ } } }, + "dto.RemoteDBInfo": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "description": { + "type": "string" + }, + "from": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "password": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "username": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, "dto.RemoteDBOption": { "type": "object", "properties": { @@ -14447,6 +14754,9 @@ const docTemplate = `{ "operate" ], "properties": { + "backup": { + "type": "boolean" + }, "backupId": { "type": "integer" }, @@ -14856,6 +15166,81 @@ const docTemplate = `{ } } }, + "request.HostToolConfig": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "content": { + "type": "string" + }, + "operate": { + "type": "string", + "enum": [ + "get", + "set" + ] + }, + "type": { + "type": "string", + "enum": [ + "supervisord" + ] + } + } + }, + "request.HostToolCreate": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "configPath": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "request.HostToolLogReq": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "supervisord" + ] + } + } + }, + "request.HostToolReq": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "operate": { + "type": "string", + "enum": [ + "status", + "restart", + "start", + "stop" + ] + }, + "type": { + "type": "string", + "enum": [ + "supervisord" + ] + } + } + }, "request.NewAppInstall": { "type": "object", "properties": { @@ -15288,6 +15673,29 @@ const docTemplate = `{ } } }, + "request.SupervisorProcessConfig": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "dir": { + "type": "string" + }, + "name": { + "type": "string" + }, + "numprocs": { + "type": "string" + }, + "operate": { + "type": "string" + }, + "user": { + "type": "string" + } + } + }, "request.WebsiteAcmeAccountCreate": { "type": "object", "required": [ diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index d61f8b046..f982d89d2 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -3903,6 +3903,21 @@ } } }, + "/databases/load/:from": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "从服务器获取", + "tags": [ + "Database Mysql" + ], + "summary": "Load mysql database from remote", + "responses": {} + } + }, "/databases/options": { "get": { "security": [ @@ -4267,6 +4282,28 @@ } } }, + "/databases/remote/:name": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取远程数据库", + "tags": [ + "Database" + ], + "summary": "Get remote databases", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dto.RemoteDBInfo" + } + } + } + } + }, "/databases/remote/del": { "post": { "security": [ @@ -4325,7 +4362,7 @@ "ApiKeyAuth": [] } ], - "description": "获取快速命令列表", + "description": "获取远程数据库列表", "tags": [ "Database" ], @@ -5916,6 +5953,241 @@ } } }, + "/host/tool": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取主机工具状态", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Get tool", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.HostToolReq" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/host/tool/config": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "操作主机工具配置文件", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Get tool config", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.HostToolConfig" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "operate" + ], + "formatEN": "[operate] tool config", + "formatZH": "[operate] 主机工具配置文件 ", + "paramKeys": [] + } + } + }, + "/host/tool/create": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "创建主机工具配置", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Create Host tool Config", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.HostToolCreate" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "type" + ], + "formatEN": "create [type] config", + "formatZH": "创建 [type] 配置", + "paramKeys": [] + } + } + }, + "/host/tool/log": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取主机工具日志", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Get tool", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.HostToolLogReq" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/host/tool/operate": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "操作主机工具", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Operate tool", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.HostToolReq" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "operate", + "type" + ], + "formatEN": "[operate] [type]", + "formatZH": "[operate] [type] ", + "paramKeys": [] + } + } + }, + "/host/tool/supervisor/process": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "操作守护进程", + "consumes": [ + "application/json" + ], + "tags": [ + "Host tool" + ], + "summary": "Create Supervisor process", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SupervisorProcessConfig" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "operate" + ], + "formatEN": "[operate] process", + "formatZH": "[operate] 守护进程 ", + "paramKeys": [] + } + } + }, "/hosts": { "post": { "security": [ @@ -13310,6 +13582,41 @@ } } }, + "dto.RemoteDBInfo": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "description": { + "type": "string" + }, + "from": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "password": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "username": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, "dto.RemoteDBOption": { "type": "object", "properties": { @@ -14440,6 +14747,9 @@ "operate" ], "properties": { + "backup": { + "type": "boolean" + }, "backupId": { "type": "integer" }, @@ -14849,6 +15159,81 @@ } } }, + "request.HostToolConfig": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "content": { + "type": "string" + }, + "operate": { + "type": "string", + "enum": [ + "get", + "set" + ] + }, + "type": { + "type": "string", + "enum": [ + "supervisord" + ] + } + } + }, + "request.HostToolCreate": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "configPath": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "request.HostToolLogReq": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "supervisord" + ] + } + } + }, + "request.HostToolReq": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "operate": { + "type": "string", + "enum": [ + "status", + "restart", + "start", + "stop" + ] + }, + "type": { + "type": "string", + "enum": [ + "supervisord" + ] + } + } + }, "request.NewAppInstall": { "type": "object", "properties": { @@ -15281,6 +15666,29 @@ } } }, + "request.SupervisorProcessConfig": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "dir": { + "type": "string" + }, + "name": { + "type": "string" + }, + "numprocs": { + "type": "string" + }, + "operate": { + "type": "string" + }, + "user": { + "type": "string" + } + } + }, "request.WebsiteAcmeAccountCreate": { "type": "object", "required": [ diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 79981d707..33dbbe430 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -1574,6 +1574,29 @@ definitions: - username - version type: object + dto.RemoteDBInfo: + properties: + address: + type: string + createdAt: + type: string + description: + type: string + from: + type: string + id: + type: integer + name: + type: string + password: + type: string + port: + type: integer + username: + type: string + version: + type: string + type: object dto.RemoteDBOption: properties: address: @@ -2320,6 +2343,8 @@ definitions: type: object request.AppInstalledOperate: properties: + backup: + type: boolean backupId: type: integer deleteBackup: @@ -2597,6 +2622,56 @@ definitions: - path - url type: object + request.HostToolConfig: + properties: + content: + type: string + operate: + enum: + - get + - set + type: string + type: + enum: + - supervisord + type: string + required: + - type + type: object + request.HostToolCreate: + properties: + configPath: + type: string + type: + type: string + required: + - type + type: object + request.HostToolLogReq: + properties: + type: + enum: + - supervisord + type: string + required: + - type + type: object + request.HostToolReq: + properties: + operate: + enum: + - status + - restart + - start + - stop + type: string + type: + enum: + - supervisord + type: string + required: + - type + type: object request.NewAppInstall: properties: advanced: @@ -2888,6 +2963,21 @@ definitions: - pageSize - path type: object + request.SupervisorProcessConfig: + properties: + command: + type: string + dir: + type: string + name: + type: string + numprocs: + type: string + operate: + type: string + user: + type: string + type: object request.WebsiteAcmeAccountCreate: properties: email: @@ -6215,6 +6305,15 @@ paths: formatEN: The description of the mysql database [name] is modified => [description] formatZH: mysql 数据库 [name] 描述信息修改 [description] paramKeys: [] + /databases/load/:from: + get: + description: 从服务器获取 + responses: {} + security: + - ApiKeyAuth: [] + summary: Load mysql database from remote + tags: + - Database Mysql /databases/options: get: consumes: @@ -6444,6 +6543,19 @@ paths: formatEN: create remote database [name][type] formatZH: 创建远程数据库 [name][type] paramKeys: [] + /databases/remote/:name: + get: + description: 获取远程数据库 + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dto.RemoteDBInfo' + security: + - ApiKeyAuth: [] + summary: Get remote databases + tags: + - Database /databases/remote/del: post: consumes: @@ -6479,7 +6591,7 @@ paths: paramKeys: [] /databases/remote/list/:type: get: - description: 获取快速命令列表 + description: 获取远程数据库列表 responses: "200": description: OK @@ -7495,6 +7607,155 @@ paths: formatEN: update SSH setting [key] => [value] formatZH: 修改 SSH 配置 [key] => [value] paramKeys: [] + /host/tool: + post: + consumes: + - application/json + description: 获取主机工具状态 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/request.HostToolReq' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Get tool + tags: + - Host tool + /host/tool/config: + post: + consumes: + - application/json + description: 操作主机工具配置文件 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/request.HostToolConfig' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Get tool config + tags: + - Host tool + x-panel-log: + BeforeFuntions: [] + bodyKeys: + - operate + formatEN: '[operate] tool config' + formatZH: '[operate] 主机工具配置文件 ' + paramKeys: [] + /host/tool/create: + post: + consumes: + - application/json + description: 创建主机工具配置 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/request.HostToolCreate' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Create Host tool Config + tags: + - Host tool + x-panel-log: + BeforeFuntions: [] + bodyKeys: + - type + formatEN: create [type] config + formatZH: 创建 [type] 配置 + paramKeys: [] + /host/tool/log: + post: + consumes: + - application/json + description: 获取主机工具日志 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/request.HostToolLogReq' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Get tool + tags: + - Host tool + /host/tool/operate: + post: + consumes: + - application/json + description: 操作主机工具 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/request.HostToolReq' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Operate tool + tags: + - Host tool + x-panel-log: + BeforeFuntions: [] + bodyKeys: + - operate + - type + formatEN: '[operate] [type]' + formatZH: '[operate] [type] ' + paramKeys: [] + /host/tool/supervisor/process: + post: + consumes: + - application/json + description: 操作守护进程 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/request.SupervisorProcessConfig' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Create Supervisor process + tags: + - Host tool + x-panel-log: + BeforeFuntions: [] + bodyKeys: + - operate + formatEN: '[operate] process' + formatZH: '[operate] 守护进程 ' + paramKeys: [] /hosts: post: consumes: diff --git a/frontend/src/api/interface/host-tool.ts b/frontend/src/api/interface/host-tool.ts new file mode 100644 index 000000000..b4a067181 --- /dev/null +++ b/frontend/src/api/interface/host-tool.ts @@ -0,0 +1,43 @@ +export namespace HostTool { + export interface HostTool { + type: string; + config: {}; + } + + export interface Supersivor extends HostTool { + configPath: string; + includeDir: string; + logPath: string; + isExist: boolean; + init: boolean; + msg: string; + version: string; + status: string; + ctlExist: boolean; + } + + export interface SupersivorConfig { + type: string; + operate: string; + content?: string; + } + + export interface SupersivorConfigRes { + type: string; + content: string; + } + + export interface SupersivorInit { + type: string; + configPath: string; + } + + export interface SupersivorProcess { + operate: string; + name: string; + command: string; + user: string; + dir: string; + numprocs: string; + } +} diff --git a/frontend/src/api/modules/host-tool.ts b/frontend/src/api/modules/host-tool.ts new file mode 100644 index 000000000..5ddba77c7 --- /dev/null +++ b/frontend/src/api/modules/host-tool.ts @@ -0,0 +1,26 @@ +import http from '@/api'; +import { HostTool } from '../interface/host-tool'; + +export const GetSupervisorStatus = () => { + return http.post(`/hosts/tool`, { type: 'supervisord', operate: 'status' }); +}; + +export const OperateSupervisor = (operate: string) => { + return http.post(`/hosts/tool/operate`, { type: 'supervisord', operate: operate }); +}; + +export const OperateSupervisorConfig = (req: HostTool.SupersivorConfig) => { + return http.post(`/hosts/tool/config`, req); +}; + +export const GetSupervisorLog = () => { + return http.post(`/hosts/tool/log`, { type: 'supervisord' }); +}; + +export const InitSupervisor = (req: HostTool.SupersivorInit) => { + return http.post(`/hosts/tool/init`, req); +}; + +export const OperateSupervisorProcess = (req: HostTool.SupersivorProcess) => { + return http.post(`/hosts/tool/supervisor/process`, req); +}; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index ceea4b500..9b770a6c1 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -254,6 +254,7 @@ const message = { processManage: 'Process', process: 'Process', network: 'Network', + supervisor: 'Supervisor', }, home: { overview: 'Overview', @@ -1651,6 +1652,22 @@ const message = { stopProcessWarn: 'Are you sure you want to end this process (PID:{0})? ', processName: 'ProcessName', }, + tool: { + supervisor: { + notSupport: 'Supervisor is not detected, please refer to the official document for installation', + list: 'Daemon process', + 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', + initWarn: + 'Because it is not compatible with the original configuration, initializing Supervisor will modify the files parameter of the configuration file, causing all existing processes to stop, please confirm the risk in advance. The modified process configuration folder is in <1Panel installation directory>/1panel/tools/supervisord/supervisor.d', + operatorHelper: 'Operation {0} will be performed on Supervisor, continue? ', + }, + }, }; export default { diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index dd997ba51..3baa56370 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -251,6 +251,7 @@ const message = { processManage: '進程管理', process: '進程', network: '網絡', + supervisor: '進程守護', }, home: { overview: '概覽', @@ -1568,6 +1569,22 @@ const message = { stopProcessWarn: '是否確定結束此進程 (PID:{0})?', processName: '進程名稱', }, + tool: { + supervisor: { + notSupport: '未檢測到 Supervisor,請參考官方文檔進行安裝', + list: '守護進程', + config: 'Supervisor 配置', + primaryConfig: '主配置文件位置', + notSupportCrl: '未檢測到 supervisorctl,請參考官方文檔進行安裝', + user: '啟動用戶', + command: '啟動命令', + dir: '運行目錄', + numprocs: '進程數量', + initWarn: + '由於無法兼容原有配置,初始化 Supervisor 會修改配置文件的 files 參數,導致已有的進程全部停止,請提前確認風險。修改後的進程配置文件夾在 <1Panel安裝目錄>/1panel/tools/supervisord/supervisor.d 中', + operatorHelper: '將對 Supervisor 進行 {0} 操作,是否繼續? ', + }, + }, }; export default { ...fit2cloudTwLocale, diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 7e3225a60..c5e9db9ee 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -251,6 +251,7 @@ const message = { processManage: '进程管理', process: '进程', network: '网络', + supervisor: '进程守护', }, home: { overview: '概览', @@ -1570,6 +1571,22 @@ const message = { stopProcessWarn: '是否确定结束此进程 (PID:{0})?', processName: '进程名称', }, + tool: { + supervisor: { + notSupport: '未检测到 Supervisor,请参考官方文档进行安装', + list: '守护进程', + config: 'Supervisor 配置', + primaryConfig: '主配置文件位置', + notSupportCrl: '未检测到 supervisorctl,请参考官方文档进行安装', + user: '启动用户', + command: '启动命令', + dir: '运行目录', + numprocs: '进程数量', + initWarn: + '由于无法兼容原有配置,初始化 Supervisor 会修改配置文件的 files 参数,导致已有的进程全部停止,请提前确认风险。修改后的进程配置文件夹在 <1Panel安装目录>/1panel/tools/supervisord/supervisor.d 中', + operatorHelper: '将对 Supervisor 进行 {0} 操作,是否继续?', + }, + }, }; export default { ...fit2cloudZhLocale, diff --git a/frontend/src/routers/modules/host.ts b/frontend/src/routers/modules/host.ts index 1ed85007a..50f60f9e7 100644 --- a/frontend/src/routers/modules/host.ts +++ b/frontend/src/routers/modules/host.ts @@ -90,6 +90,17 @@ const hostRouter = { requiresAuth: false, }, }, + { + path: '/hosts/tool/supersivor', + name: 'Supervisor', + component: () => import('@/views/host/tool/supervisor/index.vue'), + meta: { + title: 'menu.supervisor', + activeMenu: '/hosts/tool/supersivor', + keepAlive: true, + requiresAuth: false, + }, + }, { path: '/hosts/ssh/ssh', name: 'SSH', diff --git a/frontend/src/views/host/tool/index.vue b/frontend/src/views/host/tool/index.vue new file mode 100644 index 000000000..17bf3973c --- /dev/null +++ b/frontend/src/views/host/tool/index.vue @@ -0,0 +1,20 @@ + + + diff --git a/frontend/src/views/host/tool/supervisor/config/index.vue b/frontend/src/views/host/tool/supervisor/config/index.vue new file mode 100644 index 000000000..f7315d354 --- /dev/null +++ b/frontend/src/views/host/tool/supervisor/config/index.vue @@ -0,0 +1,28 @@ + + + diff --git a/frontend/src/views/host/tool/supervisor/config/log/index.vue b/frontend/src/views/host/tool/supervisor/config/log/index.vue new file mode 100644 index 000000000..d4f148fa6 --- /dev/null +++ b/frontend/src/views/host/tool/supervisor/config/log/index.vue @@ -0,0 +1,40 @@ + + + + diff --git a/frontend/src/views/host/tool/supervisor/config/source/index.vue b/frontend/src/views/host/tool/supervisor/config/source/index.vue new file mode 100644 index 000000000..654cf9929 --- /dev/null +++ b/frontend/src/views/host/tool/supervisor/config/source/index.vue @@ -0,0 +1,63 @@ + + + + diff --git a/frontend/src/views/host/tool/supervisor/create/index.vue b/frontend/src/views/host/tool/supervisor/create/index.vue new file mode 100644 index 000000000..0ec58d59e --- /dev/null +++ b/frontend/src/views/host/tool/supervisor/create/index.vue @@ -0,0 +1,108 @@ + + + diff --git a/frontend/src/views/host/tool/supervisor/index.vue b/frontend/src/views/host/tool/supervisor/index.vue new file mode 100644 index 000000000..0f44f816b --- /dev/null +++ b/frontend/src/views/host/tool/supervisor/index.vue @@ -0,0 +1,48 @@ + + + diff --git a/frontend/src/views/host/tool/supervisor/status/index.vue b/frontend/src/views/host/tool/supervisor/status/index.vue new file mode 100644 index 000000000..073190f11 --- /dev/null +++ b/frontend/src/views/host/tool/supervisor/status/index.vue @@ -0,0 +1,140 @@ + + + + diff --git a/frontend/src/views/host/tool/supervisor/status/init/index.vue b/frontend/src/views/host/tool/supervisor/status/init/index.vue new file mode 100644 index 000000000..a95e18584 --- /dev/null +++ b/frontend/src/views/host/tool/supervisor/status/init/index.vue @@ -0,0 +1,78 @@ + + +