mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 08:19:15 +08:00
feat: PHP 运行环境增加进程守护管理 (#6580)
This commit is contained in:
parent
4720bda29b
commit
7add6ab190
@ -431,3 +431,67 @@ func (b *BaseApi) GetFPMConfig(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Runtime
|
||||
// @Summary Get supervisor process
|
||||
// @Description 获取 supervisor 进程
|
||||
// @Accept json
|
||||
// @Param id path integer true "request"
|
||||
// @Success 200 {object} response.SupervisorProcess
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /runtimes/supervisor/process/:id [get]
|
||||
func (b *BaseApi) GetSupervisorProcess(c *gin.Context) {
|
||||
id, err := helper.GetParamID(c)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||
return
|
||||
}
|
||||
data, err := runtimeService.GetSupervisorProcess(id)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Runtime
|
||||
// @Summary Operate supervisor process
|
||||
// @Description 操作 supervisor 进程
|
||||
// @Accept json
|
||||
// @Param request body request.PHPSupervisorProcessConfig true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /runtimes/supervisor/process/operate [post]
|
||||
func (b *BaseApi) OperateSupervisorProcess(c *gin.Context) {
|
||||
var req request.PHPSupervisorProcessConfig
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := runtimeService.OperateSupervisorProcess(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Runtime
|
||||
// @Summary Operate supervisor process file
|
||||
// @Description 操作 supervisor 进程文件
|
||||
// @Accept json
|
||||
// @Param request body request.PHPSupervisorProcessFileReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /runtimes/supervisor/process/file/operate [post]
|
||||
func (b *BaseApi) OperateSupervisorProcessFile(c *gin.Context) {
|
||||
var req request.PHPSupervisorProcessFileReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
res, err := runtimeService.OperateSupervisorProcessFile(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ type SupervisorProcessConfig struct {
|
||||
Dir string `json:"dir"`
|
||||
Numprocs string `json:"numprocs"`
|
||||
}
|
||||
|
||||
type SupervisorProcessFileReq struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Operate string `json:"operate" validate:"required,oneof=get clear update" `
|
||||
|
@ -100,3 +100,13 @@ type FPMConfig struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Params map[string]interface{} `json:"params" validate:"required"`
|
||||
}
|
||||
|
||||
type PHPSupervisorProcessConfig struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
SupervisorProcessConfig
|
||||
}
|
||||
|
||||
type PHPSupervisorProcessFileReq struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
SupervisorProcessFileReq
|
||||
}
|
||||
|
@ -3,11 +3,13 @@ package service
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/response"
|
||||
@ -281,11 +283,6 @@ func (h *HostToolService) GetToolLog(req request.HostToolLogReq) (string, error)
|
||||
func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcessConfig) error {
|
||||
var (
|
||||
supervisordDir = path.Join(global.CONF.System.BaseDir, "1panel", "tools", "supervisord")
|
||||
logDir = path.Join(supervisordDir, "log")
|
||||
includeDir = path.Join(supervisordDir, "supervisor.d")
|
||||
outLog = path.Join(logDir, fmt.Sprintf("%s.out.log", req.Name))
|
||||
errLog = path.Join(logDir, fmt.Sprintf("%s.err.log", req.Name))
|
||||
iniPath = path.Join(includeDir, fmt.Sprintf("%s.ini", req.Name))
|
||||
fileOp = files.NewFileOp()
|
||||
)
|
||||
if req.Operate == "update" || req.Operate == "create" {
|
||||
@ -297,7 +294,22 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
||||
return buserr.WithMap("ErrUserFindErr", map[string]interface{}{"name": req.User, "err": err.Error()}, err)
|
||||
}
|
||||
}
|
||||
return handleProcess(supervisordDir, req, "")
|
||||
}
|
||||
|
||||
func handleProcess(supervisordDir string, req request.SupervisorProcessConfig, containerName string) error {
|
||||
var (
|
||||
fileOp = files.NewFileOp()
|
||||
logDir = path.Join(supervisordDir, "log")
|
||||
includeDir = path.Join(supervisordDir, "supervisor.d")
|
||||
outLog = path.Join(logDir, fmt.Sprintf("%s.out.log", req.Name))
|
||||
errLog = path.Join(logDir, fmt.Sprintf("%s.err.log", req.Name))
|
||||
iniPath = path.Join(includeDir, fmt.Sprintf("%s.ini", req.Name))
|
||||
)
|
||||
if containerName != "" {
|
||||
outLog = path.Join("/var/log/supervisor", fmt.Sprintf("%s.out.log", req.Name))
|
||||
errLog = path.Join("/var/log/supervisor", fmt.Sprintf("%s.err.log", req.Name))
|
||||
}
|
||||
switch req.Operate {
|
||||
case "create":
|
||||
if fileOp.Stat(iniPath) {
|
||||
@ -324,10 +336,10 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
||||
if err = configFile.SaveTo(iniPath); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := operateSupervisorCtl("reread", "", ""); err != nil {
|
||||
if err := operateSupervisorCtl("reread", "", "", includeDir, containerName); err != nil {
|
||||
return err
|
||||
}
|
||||
return operateSupervisorCtl("update", "", "")
|
||||
return operateSupervisorCtl("update", "", "", includeDir, containerName)
|
||||
case "update":
|
||||
configFile, err := ini.Load(iniPath)
|
||||
if err != nil {
|
||||
@ -350,52 +362,54 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
||||
if err = configFile.SaveTo(iniPath); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := operateSupervisorCtl("reread", "", ""); err != nil {
|
||||
if err := operateSupervisorCtl("reread", "", "", includeDir, containerName); err != nil {
|
||||
return err
|
||||
}
|
||||
return operateSupervisorCtl("update", "", "")
|
||||
return operateSupervisorCtl("update", "", "", includeDir, containerName)
|
||||
case "restart":
|
||||
return operateSupervisorCtl("restart", req.Name, "")
|
||||
return operateSupervisorCtl("restart", req.Name, "", includeDir, containerName)
|
||||
case "start":
|
||||
return operateSupervisorCtl("start", req.Name, "")
|
||||
return operateSupervisorCtl("start", req.Name, "", includeDir, containerName)
|
||||
case "stop":
|
||||
return operateSupervisorCtl("stop", req.Name, "")
|
||||
return operateSupervisorCtl("stop", req.Name, "", includeDir, containerName)
|
||||
case "delete":
|
||||
_ = operateSupervisorCtl("remove", "", req.Name)
|
||||
_ = files.NewFileOp().DeleteFile(iniPath)
|
||||
_ = files.NewFileOp().DeleteFile(outLog)
|
||||
_ = files.NewFileOp().DeleteFile(errLog)
|
||||
if err := operateSupervisorCtl("reread", "", ""); err != nil {
|
||||
_ = operateSupervisorCtl("remove", "", req.Name, includeDir, containerName)
|
||||
_ = fileOp.DeleteFile(iniPath)
|
||||
_ = fileOp.DeleteFile(outLog)
|
||||
_ = fileOp.DeleteFile(errLog)
|
||||
if err := operateSupervisorCtl("reread", "", "", includeDir, containerName); err != nil {
|
||||
return err
|
||||
}
|
||||
return operateSupervisorCtl("update", "", "")
|
||||
return operateSupervisorCtl("update", "", "", includeDir, containerName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error) {
|
||||
func handleProcessConfig(configDir, containerName string) ([]response.SupervisorProcessConfig, error) {
|
||||
var (
|
||||
result []response.SupervisorProcessConfig
|
||||
)
|
||||
configDir := path.Join(global.CONF.System.BaseDir, "1panel", "tools", "supervisord", "supervisor.d")
|
||||
fileList, _ := NewIFileService().GetFileList(request.FileOption{FileOption: files.FileOption{Path: configDir, Expand: true, Page: 1, PageSize: 100}})
|
||||
if len(fileList.Items) == 0 {
|
||||
return result, nil
|
||||
entries, err := os.ReadDir(configDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, configFile := range fileList.Items {
|
||||
f, err := ini.Load(configFile.Path)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("get %s file err %s", configFile.Name, err.Error())
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
if strings.HasSuffix(configFile.Name, ".ini") {
|
||||
fileName := entry.Name()
|
||||
f, err := ini.Load(path.Join(configDir, fileName))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("get %s file err %s", fileName, err.Error())
|
||||
continue
|
||||
}
|
||||
if strings.HasSuffix(fileName, ".ini") {
|
||||
config := response.SupervisorProcessConfig{}
|
||||
name := strings.TrimSuffix(configFile.Name, ".ini")
|
||||
name := strings.TrimSuffix(fileName, ".ini")
|
||||
config.Name = name
|
||||
section, err := f.GetSection(fmt.Sprintf("program:%s", name))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("get %s file section err %s", configFile.Name, err.Error())
|
||||
global.LOG.Errorf("get %s file section err %s", fileName, err.Error())
|
||||
continue
|
||||
}
|
||||
if command, _ := section.GetKey("command"); command != nil {
|
||||
@ -410,52 +424,69 @@ func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorPro
|
||||
if numprocs, _ := section.GetKey("numprocs"); numprocs != nil {
|
||||
config.Numprocs = numprocs.Value()
|
||||
}
|
||||
_ = getProcessStatus(&config)
|
||||
_ = getProcessStatus(&config, containerName)
|
||||
result = append(result, config)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error) {
|
||||
configDir := path.Join(global.CONF.System.BaseDir, "1panel", "tools", "supervisord", "supervisor.d")
|
||||
return handleProcessConfig(configDir, "")
|
||||
}
|
||||
|
||||
func (h *HostToolService) OperateSupervisorProcessFile(req request.SupervisorProcessFileReq) (string, error) {
|
||||
var (
|
||||
includeDir = path.Join(global.CONF.System.BaseDir, "1panel", "tools", "supervisord", "supervisor.d")
|
||||
)
|
||||
return handleSupervisorFile(req, includeDir, "", "")
|
||||
}
|
||||
|
||||
func handleSupervisorFile(req request.SupervisorProcessFileReq, includeDir, containerName, logFile string) (string, error) {
|
||||
var (
|
||||
fileOp = files.NewFileOp()
|
||||
group = fmt.Sprintf("program:%s", req.Name)
|
||||
configPath = path.Join(global.CONF.System.BaseDir, "1panel", "tools", "supervisord", "supervisor.d", fmt.Sprintf("%s.ini", req.Name))
|
||||
configPath = path.Join(includeDir, fmt.Sprintf("%s.ini", req.Name))
|
||||
err error
|
||||
)
|
||||
switch req.File {
|
||||
case "err.log":
|
||||
logPath, err := ini_conf.GetIniValue(configPath, group, "stderr_logfile")
|
||||
if err != nil {
|
||||
return "", err
|
||||
if logFile == "" {
|
||||
logFile, err = ini_conf.GetIniValue(configPath, group, "stderr_logfile")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
switch req.Operate {
|
||||
case "get":
|
||||
content, err := fileOp.GetContent(logPath)
|
||||
content, err := fileOp.GetContent(logFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(content), nil
|
||||
case "clear":
|
||||
if err = fileOp.WriteFile(logPath, strings.NewReader(""), 0755); err != nil {
|
||||
if err = fileOp.WriteFile(logFile, strings.NewReader(""), 0755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
case "out.log":
|
||||
logPath, err := ini_conf.GetIniValue(configPath, group, "stdout_logfile")
|
||||
if err != nil {
|
||||
return "", err
|
||||
if logFile == "" {
|
||||
logFile, err = ini_conf.GetIniValue(configPath, group, "stdout_logfile")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
switch req.Operate {
|
||||
case "get":
|
||||
content, err := fileOp.GetContent(logPath)
|
||||
content, err := fileOp.GetContent(logFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(content), nil
|
||||
case "clear":
|
||||
if err = fileOp.WriteFile(logPath, strings.NewReader(""), 0755); err != nil {
|
||||
if err = fileOp.WriteFile(logFile, strings.NewReader(""), 0755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
@ -475,17 +506,16 @@ func (h *HostToolService) OperateSupervisorProcessFile(req request.SupervisorPro
|
||||
if err := fileOp.WriteFile(configPath, strings.NewReader(req.Content), 0755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", operateSupervisorCtl("update", "", req.Name)
|
||||
return "", operateSupervisorCtl("update", "", req.Name, includeDir, containerName)
|
||||
}
|
||||
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func operateSupervisorCtl(operate, name, group string) error {
|
||||
func operateSupervisorCtl(operate, name, group, includeDir, containerName string) error {
|
||||
processNames := []string{operate}
|
||||
if name != "" {
|
||||
includeDir := path.Join(global.CONF.System.BaseDir, "1panel", "tools", "supervisord", "supervisor.d")
|
||||
f, err := ini.Load(path.Join(includeDir, fmt.Sprintf("%s.ini", name)))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -507,14 +537,21 @@ func operateSupervisorCtl(operate, name, group string) error {
|
||||
processNames = append(processNames, group)
|
||||
}
|
||||
|
||||
output, err := exec.Command("supervisorctl", processNames...).Output()
|
||||
if err != nil {
|
||||
if output != nil {
|
||||
return errors.New(string(output))
|
||||
}
|
||||
return err
|
||||
var (
|
||||
output string
|
||||
err error
|
||||
)
|
||||
if containerName != "" {
|
||||
output, err = cmd.ExecWithTimeOut(fmt.Sprintf("docker exec %s supervisorctl %s", containerName, strings.Join(processNames, " ")), 2*time.Second)
|
||||
} else {
|
||||
var out []byte
|
||||
out, err = exec.Command("supervisorctl", processNames...).Output()
|
||||
output = string(out)
|
||||
}
|
||||
return nil
|
||||
if err != nil && output != "" {
|
||||
return errors.New(output)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func getProcessName(name, numprocs string) []string {
|
||||
@ -539,14 +576,27 @@ func getProcessName(name, numprocs string) []string {
|
||||
return processNames
|
||||
}
|
||||
|
||||
func getProcessStatus(config *response.SupervisorProcessConfig) error {
|
||||
func getProcessStatus(config *response.SupervisorProcessConfig, containerName string) error {
|
||||
var (
|
||||
processNames = []string{"status"}
|
||||
output string
|
||||
err error
|
||||
)
|
||||
processNames = append(processNames, getProcessName(config.Name, config.Numprocs)...)
|
||||
output, _ := exec.Command("supervisorctl", processNames...).Output()
|
||||
lines := strings.Split(string(output), "\n")
|
||||
if containerName != "" {
|
||||
execStr := fmt.Sprintf("docker exec %s supervisorctl %s", containerName, strings.Join(processNames, " "))
|
||||
output, err = cmd.ExecWithTimeOut(execStr, 3*time.Second)
|
||||
} else {
|
||||
var out []byte
|
||||
out, err = exec.Command("supervisorctl", processNames...).Output()
|
||||
output = string(out)
|
||||
}
|
||||
if containerName == "" && err != nil {
|
||||
return err
|
||||
}
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimPrefix(line, "stdout:")
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 5 {
|
||||
status := response.ProcessStatus{
|
||||
|
@ -60,6 +60,10 @@ type IRuntimeService interface {
|
||||
GetPHPConfigFile(req request.PHPFileReq) (*response.FileInfo, error)
|
||||
UpdateFPMConfig(req request.FPMConfig) error
|
||||
GetFPMConfig(id uint) (*request.FPMConfig, error)
|
||||
|
||||
GetSupervisorProcess(id uint) ([]response.SupervisorProcessConfig, error)
|
||||
OperateSupervisorProcess(req request.PHPSupervisorProcessConfig) error
|
||||
OperateSupervisorProcessFile(req request.PHPSupervisorProcessFileReq) (string, error)
|
||||
}
|
||||
|
||||
func NewRuntimeService() IRuntimeService {
|
||||
@ -994,3 +998,32 @@ func (r *RuntimeService) GetFPMConfig(id uint) (*request.FPMConfig, error) {
|
||||
res := &request.FPMConfig{Params: params}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (r *RuntimeService) GetSupervisorProcess(id uint) ([]response.SupervisorProcessConfig, error) {
|
||||
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configDir := path.Join(constant.RuntimeDir, "php", runtime.Name, "supervisor", "supervisor.d")
|
||||
return handleProcessConfig(configDir, runtime.ContainerName)
|
||||
}
|
||||
|
||||
func (r *RuntimeService) OperateSupervisorProcess(req request.PHPSupervisorProcessConfig) error {
|
||||
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configDir := path.Join(constant.RuntimeDir, "php", runtime.Name, "supervisor")
|
||||
return handleProcess(configDir, req.SupervisorProcessConfig, runtime.ContainerName)
|
||||
}
|
||||
|
||||
func (r *RuntimeService) OperateSupervisorProcessFile(req request.PHPSupervisorProcessFileReq) (string, error) {
|
||||
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
supervisorDir := path.Join(constant.RuntimeDir, "php", runtime.Name, "supervisor")
|
||||
configDir := path.Join(supervisorDir, "supervisor.d")
|
||||
logFile := path.Join(supervisorDir, "log", fmt.Sprintf("%s.out.log", req.SupervisorProcessFileReq.Name))
|
||||
return handleSupervisorFile(req.SupervisorProcessFileReq, configDir, runtime.ContainerName, logFile)
|
||||
}
|
||||
|
@ -1344,6 +1344,7 @@ func (w WebsiteService) ChangePHPVersion(req request.WebsitePHPVersionReq) error
|
||||
server := servers[0]
|
||||
|
||||
if req.RuntimeID > 0 {
|
||||
server.RemoveDirective("location", []string{"~", "[^/]\\.php(/|$)"})
|
||||
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.RuntimeID))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -1462,11 +1463,7 @@ func (w WebsiteService) UpdateSitePermission(req request.WebsiteUpdateDirPermiss
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
absoluteIndexPath := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "index")
|
||||
absoluteIndexPath := GetSitePath(website, SiteIndexDir)
|
||||
chownCmd := fmt.Sprintf("chown -R %s:%s %s", req.User, req.Group, absoluteIndexPath)
|
||||
if cmd.HasNoPasswordSudo() {
|
||||
chownCmd = fmt.Sprintf("sudo %s", chownCmd)
|
||||
|
@ -41,5 +41,9 @@ func (r *RuntimeRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
groupRouter.POST("/php/file", baseApi.GetPHPConfigFile)
|
||||
groupRouter.POST("/php/fpm/config", baseApi.UpdateFPMConfig)
|
||||
groupRouter.GET("/php/fpm/config/:id", baseApi.GetFPMConfig)
|
||||
|
||||
groupRouter.GET("/supervisor/process/:id", baseApi.GetSupervisorProcess)
|
||||
groupRouter.POST("/supervisor/process", baseApi.OperateSupervisorProcess)
|
||||
groupRouter.POST("/supervisor/process/file", baseApi.OperateSupervisorProcessFile)
|
||||
}
|
||||
}
|
||||
|
@ -171,4 +171,28 @@ export namespace Runtime {
|
||||
id: number;
|
||||
params: any;
|
||||
}
|
||||
|
||||
export interface ProcessReq {
|
||||
operate: string;
|
||||
name: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface ProcessFileReq {
|
||||
operate: string;
|
||||
name: string;
|
||||
content?: string;
|
||||
file: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface SupersivorProcess {
|
||||
operate: string;
|
||||
name: string;
|
||||
command: string;
|
||||
user: string;
|
||||
dir: string;
|
||||
numprocs: string;
|
||||
id: number;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { Runtime } from '../interface/runtime';
|
||||
import { TimeoutEnum } from '@/enums/http-enum';
|
||||
import { App } from '@/api/interface/app';
|
||||
import { File } from '../interface/file';
|
||||
import { HostTool } from '../interface/host-tool';
|
||||
|
||||
export const SearchRuntimes = (req: Runtime.RuntimeReq) => {
|
||||
return http.post<ResPage<Runtime.RuntimeDTO>>(`/runtimes/search`, req);
|
||||
@ -104,3 +105,19 @@ export const UpdateFPMConfig = (req: Runtime.FPMConfig) => {
|
||||
export const GetFPMConfig = (id: number) => {
|
||||
return http.get<Runtime.FPMConfig>(`/runtimes/php/fpm/config/${id}`);
|
||||
};
|
||||
|
||||
export const GetSupervisorProcess = (id: number) => {
|
||||
return http.get<HostTool.ProcessStatus[]>(`/runtimes/supervisor/process/${id}`);
|
||||
};
|
||||
|
||||
export const OperateSupervisorProcess = (req: Runtime.ProcessReq) => {
|
||||
return http.post(`/runtimes/supervisor/process`, req, TimeoutEnum.T_60S);
|
||||
};
|
||||
|
||||
export const OperateSupervisorProcessFile = (req: Runtime.ProcessFileReq) => {
|
||||
return http.post<string>(`/runtimes/supervisor/process/file`, req, TimeoutEnum.T_60S);
|
||||
};
|
||||
|
||||
export const CreateSupervisorProcess = (req: Runtime.SupersivorProcess) => {
|
||||
return http.post(`/runtimes/supervisor/process`, req);
|
||||
};
|
||||
|
@ -85,6 +85,8 @@ const size = computed(() => {
|
||||
return '50%';
|
||||
case 'full':
|
||||
return '100%';
|
||||
case '60%':
|
||||
return '60%';
|
||||
default:
|
||||
return '50%';
|
||||
}
|
||||
|
@ -112,6 +112,7 @@
|
||||
<ExtManagement ref="extManagementRef" @close="search" />
|
||||
<ComposeLogs ref="composeLogRef" />
|
||||
<Config ref="configRef" />
|
||||
<Supervisor ref="supervisorRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -133,6 +134,7 @@ import RouterMenu from '../index.vue';
|
||||
import Log from '@/components/log-dialog/index.vue';
|
||||
import ComposeLogs from '@/components/compose-log/index.vue';
|
||||
import Config from '@/views/website/runtime/php/config/index.vue';
|
||||
import Supervisor from '@/views/website/runtime/php/supervisor/index.vue';
|
||||
|
||||
const paginationConfig = reactive({
|
||||
cacheSizeKey: 'runtime-page-size',
|
||||
@ -157,6 +159,7 @@ const loading = ref(false);
|
||||
const items = ref<Runtime.RuntimeDTO[]>([]);
|
||||
const composeLogRef = ref();
|
||||
const configRef = ref();
|
||||
const supervisorRef = ref();
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
@ -218,6 +221,15 @@ const buttons = [
|
||||
return row.status === 'building';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('menu.supervisor'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
openSupervisor(row);
|
||||
},
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
return row.status === 'building';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
@ -255,6 +267,10 @@ const openConfig = (row: Runtime.Runtime) => {
|
||||
configRef.value.acceptParams(row);
|
||||
};
|
||||
|
||||
const openSupervisor = (row: Runtime.Runtime) => {
|
||||
supervisorRef.value.acceptParams(row.id);
|
||||
};
|
||||
|
||||
const openLog = (row: Runtime.RuntimeDTO) => {
|
||||
if (row.status == 'running') {
|
||||
composeLogRef.value.acceptParams({ compose: row.path + '/docker-compose.yml', resource: row.name });
|
||||
@ -344,7 +360,7 @@ onMounted(() => {
|
||||
search();
|
||||
timer = setInterval(() => {
|
||||
search();
|
||||
}, 10000 * 3);
|
||||
}, 10000 * 1);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
|
@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<DrawerPro
|
||||
v-model="open"
|
||||
:header="process.operate == 'create' ? $t('commons.button.create') : $t('commons.button.edit')"
|
||||
:back="handleClose"
|
||||
size="small"
|
||||
>
|
||||
<el-form
|
||||
ref="processForm"
|
||||
label-position="top"
|
||||
:model="process"
|
||||
label-width="100px"
|
||||
:rules="rules"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-form-item :label="$t('commons.table.name')" prop="name">
|
||||
<el-input v-model.trim="process.name" :disabled="process.operate == 'update'"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('tool.supervisor.user')" prop="user">
|
||||
<el-input v-model.trim="process.user"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('tool.supervisor.dir')" prop="dir">
|
||||
<el-input v-model.trim="process.dir">
|
||||
<template #prepend><FileList @choose="getPath" :dir="true"></FileList></template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('tool.supervisor.command')" prop="command">
|
||||
<el-input v-model="process.command"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('tool.supervisor.numprocs')" prop="numprocsNum">
|
||||
<el-input type="number" v-model.number="process.numprocsNum"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit(processForm)" :disabled="loading">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</DrawerPro>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { CreateSupervisorProcess } from '@/api/modules/runtime';
|
||||
import { Rules, checkNumberRange } from '@/global/form-rules';
|
||||
import FileList from '@/components/file-list/index.vue';
|
||||
import i18n from '@/lang';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { ref } from 'vue';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { HostTool } from '@/api/interface/host-tool';
|
||||
|
||||
const open = ref(false);
|
||||
const loading = ref(false);
|
||||
const processForm = ref<FormInstance>();
|
||||
const rules = ref({
|
||||
name: [Rules.requiredInput, Rules.supervisorName],
|
||||
dir: [Rules.requiredInput],
|
||||
command: [Rules.requiredInput],
|
||||
user: [Rules.requiredInput],
|
||||
numprocsNum: [Rules.requiredInput, Rules.integerNumber, checkNumberRange(1, 9999)],
|
||||
});
|
||||
const initData = (runtimeID: number) => ({
|
||||
operate: 'create',
|
||||
name: '',
|
||||
command: '',
|
||||
user: 'www-data',
|
||||
dir: '',
|
||||
numprocsNum: 1,
|
||||
numprocs: '1',
|
||||
id: runtimeID,
|
||||
});
|
||||
const process = ref(initData(0));
|
||||
const em = defineEmits(['close']);
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
resetForm();
|
||||
em('close', open);
|
||||
};
|
||||
|
||||
const getPath = (path: string) => {
|
||||
process.value.dir = path;
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
process.value = initData(0);
|
||||
processForm.value?.resetFields();
|
||||
};
|
||||
|
||||
const acceptParams = (operate: string, config: HostTool.SupersivorProcess, id: number) => {
|
||||
process.value = initData(id);
|
||||
if (operate == 'update') {
|
||||
process.value = {
|
||||
operate: 'update',
|
||||
name: config.name,
|
||||
command: config.command,
|
||||
user: config.user,
|
||||
dir: config.dir,
|
||||
numprocsNum: 1,
|
||||
numprocs: config.numprocs,
|
||||
id: id,
|
||||
};
|
||||
process.value.numprocsNum = Number(config.numprocs);
|
||||
}
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
process.value.numprocs = String(process.value.numprocsNum);
|
||||
CreateSupervisorProcess(process.value)
|
||||
.then(() => {
|
||||
open.value = false;
|
||||
em('close', open);
|
||||
MsgSuccess(i18n.global.t('commons.msg.' + process.value.operate + 'Success'));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
148
frontend/src/views/website/runtime/php/supervisor/file/index.vue
Normal file
148
frontend/src/views/website/runtime/php/supervisor/file/index.vue
Normal file
@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<DrawerPro v-model="open" :header="title" :back="handleClose" size="large" :fullScreen="true">
|
||||
<template #content>
|
||||
<div v-if="req.file != 'config'">
|
||||
<el-tabs v-model="req.file" type="card" @tab-click="handleChange">
|
||||
<el-tab-pane :label="$t('logs.runLog')" name="out.log"></el-tab-pane>
|
||||
<el-tab-pane :label="$t('logs.errLog')" name="err.log"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-checkbox border v-model="tailLog" class="float-left" @change="changeTail">
|
||||
{{ $t('commons.button.watch') }}
|
||||
</el-checkbox>
|
||||
<el-button class="ml-5" @click="cleanLog" icon="Delete">
|
||||
{{ $t('commons.button.clean') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<br />
|
||||
<div v-loading="loading">
|
||||
<CodemirrorPro class="mt-5" v-model="content" :heightDiff="400"></CodemirrorPro>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" :disabled="loading" @click="submit()" v-if="req.file === 'config'">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</DrawerPro>
|
||||
<OpDialog ref="opRef" @search="getContent" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onUnmounted, reactive, ref } from 'vue';
|
||||
import { OperateSupervisorProcessFile } from '@/api/modules/runtime';
|
||||
import i18n from '@/lang';
|
||||
import { TabsPaneContext } from 'element-plus';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref(false);
|
||||
const content = ref('');
|
||||
const tailLog = ref(false);
|
||||
const open = ref(false);
|
||||
const req = reactive({
|
||||
name: '',
|
||||
file: 'conf',
|
||||
operate: '',
|
||||
content: '',
|
||||
id: 0,
|
||||
});
|
||||
const title = ref('');
|
||||
const opRef = ref();
|
||||
let timer: NodeJS.Timer | null = null;
|
||||
const em = defineEmits(['search']);
|
||||
|
||||
const getContent = () => {
|
||||
loading.value = true;
|
||||
OperateSupervisorProcessFile(req)
|
||||
.then((res) => {
|
||||
content.value = res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const handleChange = (tab: TabsPaneContext) => {
|
||||
req.file = tab.props.name.toString();
|
||||
getContent();
|
||||
};
|
||||
|
||||
const changeTail = () => {
|
||||
if (tailLog.value) {
|
||||
timer = setInterval(() => {
|
||||
getContent();
|
||||
}, 1000 * 5);
|
||||
} else {
|
||||
onCloseLog();
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
content.value = '';
|
||||
open.value = false;
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
const updateReq = {
|
||||
name: req.name,
|
||||
operate: 'update',
|
||||
file: req.file,
|
||||
content: content.value,
|
||||
id: req.id,
|
||||
};
|
||||
loading.value = true;
|
||||
OperateSupervisorProcessFile(updateReq)
|
||||
.then(() => {
|
||||
em('search');
|
||||
open.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const acceptParams = (name: string, file: string, operate: string, runtimeID: number) => {
|
||||
req.name = name;
|
||||
req.file = file;
|
||||
req.operate = operate;
|
||||
req.id = runtimeID;
|
||||
|
||||
title.value = file == 'config' ? i18n.global.t('website.source') : i18n.global.t('commons.button.log');
|
||||
getContent();
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const cleanLog = async () => {
|
||||
let log = req.file === 'out.log' ? i18n.global.t('logs.runLog') : i18n.global.t('logs.errLog');
|
||||
opRef.value.acceptParams({
|
||||
title: i18n.global.t('commons.msg.clean'),
|
||||
names: [req.name],
|
||||
msg: i18n.global.t('commons.msg.operatorHelper', [log, i18n.global.t('commons.msg.clean')]),
|
||||
api: OperateSupervisorProcessFile,
|
||||
params: { name: req.name, operate: 'clear', file: req.file },
|
||||
});
|
||||
};
|
||||
|
||||
const onCloseLog = async () => {
|
||||
tailLog.value = false;
|
||||
clearInterval(Number(timer));
|
||||
timer = null;
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
onCloseLog();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.fullScreen {
|
||||
border: none;
|
||||
}
|
||||
</style>
|
316
frontend/src/views/website/runtime/php/supervisor/index.vue
Normal file
316
frontend/src/views/website/runtime/php/supervisor/index.vue
Normal file
@ -0,0 +1,316 @@
|
||||
<template>
|
||||
<DrawerPro v-model="open" :header="$t('tool.supervisor.list')" size="60%" :back="handleClose">
|
||||
<template #content>
|
||||
<ComplexTable :data="data" v-loading="loading">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" @click="openCreate">
|
||||
{{ $t('commons.button.create') + $t('tool.supervisor.list') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
fix
|
||||
prop="name"
|
||||
min-width="80px"
|
||||
show-overflow-tooltip
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('tool.supervisor.command')"
|
||||
prop="command"
|
||||
min-width="100px"
|
||||
fix
|
||||
show-overflow-tooltip
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('tool.supervisor.dir')"
|
||||
prop="dir"
|
||||
min-width="100px"
|
||||
fix
|
||||
show-overflow-tooltip
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('tool.supervisor.user')"
|
||||
prop="user"
|
||||
show-overflow-tooltip
|
||||
min-width="60px"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('tool.supervisor.numprocs')"
|
||||
prop="numprocs"
|
||||
min-width="60px"
|
||||
></el-table-column>
|
||||
<el-table-column :label="$t('tool.supervisor.manage')" min-width="80px">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.status && row.status.length > 0 && row.hasLoad">
|
||||
<el-button
|
||||
v-if="checkStatus(row.status) === 'RUNNING'"
|
||||
link
|
||||
type="success"
|
||||
:icon="VideoPlay"
|
||||
@click="operate('stop', row.name)"
|
||||
>
|
||||
{{ $t('commons.status.running') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else-if="checkStatus(row.status) === 'WARNING'"
|
||||
link
|
||||
type="warning"
|
||||
:icon="RefreshRight"
|
||||
@click="operate('restart', row.name)"
|
||||
>
|
||||
{{ $t('commons.status.unhealthy') }}
|
||||
</el-button>
|
||||
<el-button v-else link type="danger" :icon="VideoPause" @click="operate('start', row.name)">
|
||||
{{ $t('commons.status.stopped') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="!row.hasLoad">
|
||||
<el-button link loading></el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.status')" min-width="60px">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.hasLoad">
|
||||
<el-popover placement="bottom" :width="600" trigger="hover">
|
||||
<template #reference>
|
||||
<el-button type="primary" link v-if="row.status.length > 1">
|
||||
{{ $t('website.check') }}
|
||||
</el-button>
|
||||
<el-button type="primary" link v-else>
|
||||
<span>{{ $t('tool.supervisor.' + row.status[0].status) }}</span>
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table :data="row.status">
|
||||
<el-table-column
|
||||
property="name"
|
||||
:label="$t('commons.table.name')"
|
||||
fix
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
property="status"
|
||||
:label="$t('tool.supervisor.statusCode')"
|
||||
width="100px"
|
||||
/>
|
||||
<el-table-column property="PID" label="PID" width="100px" />
|
||||
<el-table-column
|
||||
property="uptime"
|
||||
:label="$t('tool.supervisor.uptime')"
|
||||
width="100px"
|
||||
/>
|
||||
<el-table-column
|
||||
property="msg"
|
||||
:label="$t('tool.supervisor.msg')"
|
||||
fix
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
</el-table>
|
||||
</el-popover>
|
||||
</div>
|
||||
<div v-if="!row.hasLoad">
|
||||
<el-button link loading></el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations
|
||||
:ellipsis="6"
|
||||
:buttons="buttons"
|
||||
:label="$t('commons.table.operate')"
|
||||
:fixed="mobile ? false : 'right'"
|
||||
width="280px"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
</template>
|
||||
</DrawerPro>
|
||||
<File ref="fileRef" @search="search" />
|
||||
<Create ref="createRef" @close="search" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from '@vue/runtime-core';
|
||||
import { computed } from 'vue';
|
||||
import Create from './create/index.vue';
|
||||
import File from './file/index.vue';
|
||||
import { GetSupervisorProcess, OperateSupervisorProcess } from '@/api/modules/runtime';
|
||||
import { GlobalStore } from '@/store';
|
||||
import i18n from '@/lang';
|
||||
import { HostTool } from '@/api/interface/host-tool';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { VideoPlay, VideoPause, RefreshRight } from '@element-plus/icons-vue';
|
||||
const globalStore = GlobalStore();
|
||||
|
||||
const loading = ref(false);
|
||||
const fileRef = ref();
|
||||
const data = ref();
|
||||
const createRef = ref();
|
||||
const dataLoading = ref(false);
|
||||
const open = ref(false);
|
||||
const runtimeID = ref(0);
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
};
|
||||
|
||||
const acceptParams = async (id: number) => {
|
||||
runtimeID.value = id;
|
||||
search();
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const openCreate = () => {
|
||||
createRef.value.acceptParams('create', undefined, runtimeID.value);
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
let needLoadStatus = false;
|
||||
dataLoading.value = true;
|
||||
try {
|
||||
const res = await GetSupervisorProcess(runtimeID.value);
|
||||
data.value = res.data;
|
||||
for (const process of data.value) {
|
||||
if (process.status && process.status.length > 0) {
|
||||
process.hasLoad = true;
|
||||
} else {
|
||||
process.hasLoad = false;
|
||||
needLoadStatus = true;
|
||||
}
|
||||
}
|
||||
if (needLoadStatus) {
|
||||
setTimeout(loadStatus, 1000);
|
||||
}
|
||||
} catch (error) {
|
||||
} finally {
|
||||
dataLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadStatus = async () => {
|
||||
let needLoadStatus = false;
|
||||
try {
|
||||
const res = await GetSupervisorProcess(runtimeID.value);
|
||||
const stats = res.data || [];
|
||||
for (const process of data.value) {
|
||||
for (const item of stats) {
|
||||
if (process.name === item.name) {
|
||||
if (item.status && item.status.length > 0) {
|
||||
process.status = item.status;
|
||||
process.hasLoad = true;
|
||||
} else {
|
||||
needLoadStatus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needLoadStatus) {
|
||||
setTimeout(loadStatus, 20000);
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const mobile = computed(() => {
|
||||
return globalStore.isMobile();
|
||||
});
|
||||
|
||||
const checkStatus = (status: HostTool.ProcessStatus[]): string => {
|
||||
if (!status || status.length === 0) return 'STOPPED';
|
||||
|
||||
const statusCounts = status.reduce((acc, curr) => {
|
||||
acc[curr.status] = (acc[curr.status] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
if (statusCounts['STARTING']) return 'STARTING';
|
||||
if (statusCounts['RUNNING'] === status.length) return 'RUNNING';
|
||||
if (statusCounts['RUNNING'] > 0) return 'WARNING';
|
||||
return 'STOPPED';
|
||||
};
|
||||
|
||||
const operate = async (operation: string, name: string) => {
|
||||
try {
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('tool.supervisor.operatorHelper', [name, i18n.global.t('app.' + operation)]),
|
||||
i18n.global.t('app.' + operation),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
},
|
||||
)
|
||||
.then(() => {
|
||||
loading.value = true;
|
||||
OperateSupervisorProcess({ operate: operation, name: name, id: runtimeID.value })
|
||||
.then(() => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
search();
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const getFile = (name: string, file: string, runtimeID: number) => {
|
||||
fileRef.value.acceptParams(name, file, 'get', runtimeID);
|
||||
};
|
||||
|
||||
const edit = (row: HostTool.SupersivorProcess) => {
|
||||
createRef.value.acceptParams('update', row);
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.edit'),
|
||||
click: function (row: HostTool.SupersivorProcess) {
|
||||
edit(row);
|
||||
},
|
||||
show: function (row: HostTool.SupersivorProcess) {
|
||||
return row.name != 'php-fpm';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('website.proxyFile'),
|
||||
click: function (row: HostTool.SupersivorProcess) {
|
||||
getFile(row.name, 'config', runtimeID.value);
|
||||
},
|
||||
show: function (row: HostTool.SupersivorProcess) {
|
||||
return row.name != 'php-fpm';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('website.log'),
|
||||
click: function (row: HostTool.SupersivorProcess) {
|
||||
getFile(row.name, 'out.log', runtimeID.value);
|
||||
},
|
||||
show: function (row: HostTool.SupersivorProcess) {
|
||||
return row.name != 'php-fpm';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.restart'),
|
||||
click: function (row: HostTool.SupersivorProcess) {
|
||||
operate('restart', row.name);
|
||||
},
|
||||
show: function (row: HostTool.SupersivorProcess) {
|
||||
return row.name != 'php-fpm';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: function (row: HostTool.SupersivorProcess) {
|
||||
operate('delete', row.name);
|
||||
},
|
||||
show: function (row: HostTool.SupersivorProcess) {
|
||||
return row.name != 'php-fpm';
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
@ -43,7 +43,7 @@
|
||||
:label="'PHP'"
|
||||
v-if="(website.type === 'runtime' && website.runtimeType === 'php') || website.type === 'static'"
|
||||
>
|
||||
<PHP :website="website" v-if="tabIndex == '12'"></PHP>
|
||||
<PHP :website="website" v-if="tabIndex == '13'"></PHP>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
@ -76,6 +76,7 @@ const submit = async (form: FormInstance) => {
|
||||
taskID: taskID,
|
||||
mirror: build.value.mirror,
|
||||
});
|
||||
handleClose();
|
||||
openTaskLog(taskID);
|
||||
} catch (error) {}
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user