1Panel/backend/app/service/host_tool.go

260 lines
7.5 KiB
Go
Raw Normal View History

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)))
}