Skip to content

Commit 79020ab

Browse files
authored
feat(systemctl): implement service manager initialization and command execution (#8380)
* feat(systemctl): 实现服务管理器初始化和命令执行 - 新增 systemctl 包,实现对 systemd、openrc 和 sysvinit 三种服务管理器的支持 - 添加服务状态检查、启动、停止、重启和启用/禁用功能 - 实现服务发现和智能服务名处理 - 添加配置文件查看功能 - 优化错误处理和日志记录 * refactor(system): 重构系统服务管理逻辑 - 引入 systemctl 工具包以统一处理系统服务 - 优化服务状态获取、配置文件路径解析等逻辑 - 重构 HostToolService 中的 GetToolStatus 方法 - 更新 DockerService、SettingService 等相关服务的处理方式 - 调整快照创建和恢复过程中的服务处理逻辑 * feat(utils): 添加目录复制功能并优化文件复制逻辑 - 新增 CopyDirs 函数,用于复制整个目录及其内容 - 添加对符号链接的复制支持 - 实现通用的 Copy 函数,根据文件类型自动选择 CopyFile 或 CopyDirs - 在 CopyFile 函数中增加对源文件是目录的检查和错误提示 * refactortoolbox: 重构 Fail2ban 和 Pure-FTPd 的管理逻辑 - 优化了 Fail2ban 和 Pure-FTPd 的启动、停止、重启等操作的实现 - 改进了 Fail2ban 版本信息的获取方法 - 统一了错误处理和日志记录的格式 - 调整了部分导入的包,提高了代码的可维护性 * build: 禁用 CGO 以提高构建性能和兼容性 - 在 Linux 后端构建命令中添加 CGO_ENABLED=0 环境变量 - 此修改可以提高构建速度,并确保生成的二进制文件在没有 C 库依赖的环境中也能运行 * refactor(docker): 重构 Docker 服务的重启和操作逻辑 - 添加 isDockerSnapInstalled 函数来判断 Docker 是否通过 Snap 安装 - 在 OperateDocker 和 restartDocker 函数中增加对 Snap 安装的处理 - 移除未使用的 getDockerRestartCommand 函数 * fix(service): 优化快照恢复后的服务重启逻辑 - 在使用 systemd 管理服务时,增加 daemon-reload 操作以确保服务配置更新 - 重启 1panel 服务,以应用快照恢复的更改 * refactor(server): 支持非 systemd 系统的恢复操作 - 增加 isSystemd 函数判断系统是否为 systemd 类型 - 根据系统类型选择性地恢复服务文件 - 兼容 systemd 和非 systemd 系统的恢复流程 * fix(upgrade): 优化升级过程中的服务重启逻辑 - 移动服务重启逻辑到版本号更新之后,修复因提前重启导致的版本号未更新BUG。 - 在 systemctl 重启之前添加 daemon-reload 命令 --------- Co-authored-by: gcsong023 <[email protected]>
1 parent 83ef41c commit 79020ab

19 files changed

+2045
-425
lines changed

Diff for: Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ build_frontend:
2323

2424
build_backend_on_linux:
2525
cd $(SERVER_PATH) \
26-
&& GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
26+
&& CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
2727

2828
build_backend_on_darwin:
2929
cd $(SERVER_PATH) \

Diff for: backend/app/service/clam.go

+105-131
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package service
22

33
import (
4-
"bufio"
54
"fmt"
65
"os"
76
"os/exec"
@@ -28,14 +27,14 @@ import (
2827
)
2928

3029
const (
31-
clamServiceNameCentOs = "[email protected]"
32-
clamServiceNameUbuntu = "clamav-daemon.service"
33-
freshClamService = "clamav-freshclam.service"
34-
resultDir = "clamav"
30+
clamServiceKey = "clam"
31+
freshClamServiceKey = "freshclam"
32+
resultDir = "clamav"
3533
)
3634

3735
type ClamService struct {
38-
serviceName string
36+
serviceName string
37+
freshClamService string
3938
}
4039

4140
type IClamService interface {
@@ -63,23 +62,32 @@ func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) {
6362
var baseInfo dto.ClamBaseInfo
6463
baseInfo.Version = "-"
6564
baseInfo.FreshVersion = "-"
66-
exist1, _ := systemctl.IsExist(clamServiceNameCentOs)
67-
if exist1 {
68-
c.serviceName = clamServiceNameCentOs
69-
baseInfo.IsExist = true
70-
baseInfo.IsActive, _ = systemctl.IsActive(clamServiceNameCentOs)
71-
}
72-
exist2, _ := systemctl.IsExist(clamServiceNameUbuntu)
73-
if exist2 {
74-
c.serviceName = clamServiceNameUbuntu
75-
baseInfo.IsExist = true
76-
baseInfo.IsActive, _ = systemctl.IsActive(clamServiceNameUbuntu)
77-
}
78-
freshExist, _ := systemctl.IsExist(freshClamService)
79-
if freshExist {
80-
baseInfo.FreshIsExist = true
81-
baseInfo.FreshIsActive, _ = systemctl.IsActive(freshClamService)
65+
clamSvc, err := systemctl.GetServiceName(clamServiceKey)
66+
if err != nil {
67+
baseInfo.IsExist = false
68+
return baseInfo, nil
69+
}
70+
c.serviceName = clamSvc
71+
isExist, err := systemctl.IsExist(c.serviceName)
72+
if err != nil {
73+
baseInfo.IsExist = false
74+
}
75+
baseInfo.IsExist = isExist
76+
baseInfo.IsActive, _ = systemctl.IsActive(clamSvc)
77+
78+
freshSvc, err := systemctl.GetServiceName(freshClamServiceKey)
79+
if err != nil {
80+
baseInfo.FreshIsExist = false
81+
return baseInfo, nil
82+
}
83+
c.freshClamService = freshSvc
84+
freshisExist, err := systemctl.IsExist(c.freshClamService)
85+
if err != nil {
86+
baseInfo.FreshIsExist = false
8287
}
88+
baseInfo.FreshIsExist = freshisExist
89+
baseInfo.FreshIsActive, _ = systemctl.IsActive(freshSvc)
90+
8391
if !cmd.Which("clamdscan") {
8492
baseInfo.IsActive = false
8593
}
@@ -110,22 +118,27 @@ func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) {
110118
}
111119

112120
func (c *ClamService) Operate(operate string) error {
121+
var err error
113122
switch operate {
114-
case "start", "restart", "stop":
115-
stdout, err := cmd.Execf("systemctl %s %s", operate, c.serviceName)
116-
if err != nil {
117-
return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, stdout)
118-
}
119-
return nil
120-
case "fresh-start", "fresh-restart", "fresh-stop":
121-
stdout, err := cmd.Execf("systemctl %s %s", strings.TrimPrefix(operate, "fresh-"), freshClamService)
122-
if err != nil {
123-
return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, stdout)
124-
}
125-
return nil
123+
case "start":
124+
err = systemctl.Start(c.serviceName)
125+
case "stop":
126+
err = systemctl.Stop(c.serviceName)
127+
case "restart":
128+
err = systemctl.Restart(c.serviceName)
129+
case "fresh-start":
130+
err = systemctl.Start(c.freshClamService)
131+
case "fresh-stop":
132+
err = systemctl.Stop(c.freshClamService)
133+
case "fresh-restart":
134+
err = systemctl.Restart(c.freshClamService)
126135
default:
127-
return fmt.Errorf("not support such operation: %v", operate)
136+
return fmt.Errorf("unsupported operation: %s", operate)
128137
}
138+
if err != nil {
139+
return fmt.Errorf("%s %s failed: %v", operate, c.serviceName, err)
140+
}
141+
return nil
129142
}
130143

131144
func (c *ClamService) SearchWithPage(req dto.SearchClamWithPage) (int64, interface{}, error) {
@@ -432,102 +445,80 @@ func (c *ClamService) LoadFile(req dto.ClamFileReq) (string, error) {
432445
filePath := ""
433446
switch req.Name {
434447
case "clamd":
435-
if c.serviceName == clamServiceNameUbuntu {
436-
filePath = "/etc/clamav/clamd.conf"
437-
} else {
438-
filePath = "/etc/clamd.d/scan.conf"
439-
}
448+
filePath = c.getConfigPath("clamd")
440449
case "clamd-log":
441450
filePath = c.loadLogPath("clamd-log")
442-
if len(filePath) != 0 {
443-
break
444-
}
445-
if c.serviceName == clamServiceNameUbuntu {
446-
filePath = "/var/log/clamav/clamav.log"
447-
} else {
448-
filePath = "/var/log/clamd.scan"
449-
}
450451
case "freshclam":
451-
if c.serviceName == clamServiceNameUbuntu {
452-
filePath = "/etc/clamav/freshclam.conf"
453-
} else {
454-
filePath = "/etc/freshclam.conf"
455-
}
452+
filePath = c.getConfigPath("freshclam")
456453
case "freshclam-log":
457454
filePath = c.loadLogPath("freshclam-log")
458-
if len(filePath) != 0 {
459-
break
460-
}
461-
if c.serviceName == clamServiceNameUbuntu {
462-
filePath = "/var/log/clamav/freshclam.log"
463-
} else {
464-
filePath = "/var/log/freshclam.log"
465-
}
466455
default:
467-
return "", fmt.Errorf("not support such type")
468-
}
469-
if _, err := os.Stat(filePath); err != nil {
470-
return "", buserr.New("ErrHttpReqNotFound")
456+
return "", fmt.Errorf("unsupported file type")
471457
}
472-
var tail string
473-
if req.Tail != "0" {
474-
tail = req.Tail
475-
} else {
476-
tail = "+1"
477-
}
478-
cmd := exec.Command("tail", "-n", tail, filePath)
479-
stdout, err := cmd.CombinedOutput()
458+
459+
content, err := systemctl.ViewConfig(filePath, systemctl.ConfigOption{TailLines: req.Tail})
480460
if err != nil {
481-
return "", fmt.Errorf("tail -n %v failed, err: %v", req.Tail, err)
461+
return "", buserr.New("ErrHttpReqNotFound")
482462
}
483-
return string(stdout), nil
463+
return content, nil
484464
}
485465

486466
func (c *ClamService) UpdateFile(req dto.UpdateByNameAndFile) error {
487-
filePath := ""
488-
service := ""
467+
var (
468+
filePath string
469+
service string
470+
)
471+
489472
switch req.Name {
490473
case "clamd":
491-
if c.serviceName == clamServiceNameUbuntu {
492-
service = clamServiceNameUbuntu
493-
filePath = "/etc/clamav/clamd.conf"
494-
} else {
495-
service = clamServiceNameCentOs
496-
filePath = "/etc/clamd.d/scan.conf"
497-
}
474+
filePath = c.getConfigPath("clamd")
475+
service = c.serviceName
498476
case "freshclam":
499-
if c.serviceName == clamServiceNameUbuntu {
500-
filePath = "/etc/clamav/freshclam.conf"
501-
} else {
502-
filePath = "/etc/freshclam.conf"
503-
}
504-
service = "clamav-freshclam.service"
477+
filePath = c.getConfigPath("freshclam")
478+
service = c.freshClamService
505479
default:
506-
return fmt.Errorf("not support such type")
480+
return fmt.Errorf("unsupported file type")
507481
}
482+
508483
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC, 0640)
509484
if err != nil {
510485
return err
511486
}
512487
defer file.Close()
513-
write := bufio.NewWriter(file)
514-
_, _ = write.WriteString(req.File)
515-
write.Flush()
516488

517-
_ = systemctl.Restart(service)
489+
if _, err := file.WriteString(req.File); err != nil {
490+
return err
491+
}
492+
493+
if err := systemctl.Restart(service); err != nil {
494+
return fmt.Errorf("restart %s failed: %v", service, err)
495+
}
518496
return nil
519497
}
520498

499+
func (c *ClamService) getConfigPath(confType string) string {
500+
switch confType {
501+
case "clamd":
502+
if _, err := os.Stat("/etc/clamav/clamd.conf"); err == nil {
503+
return "/etc/clamav/clamd.conf"
504+
}
505+
return "/etc/clamd.d/scan.conf"
506+
case "freshclam":
507+
if _, err := os.Stat("/etc/clamav/freshclam.conf"); err == nil {
508+
return "/etc/clamav/freshclam.conf"
509+
}
510+
return "/etc/freshclam.conf"
511+
default:
512+
return ""
513+
}
514+
}
515+
521516
func StopAllCronJob(withCheck bool) bool {
522517
if withCheck {
523518
isActive := false
524-
exist1, _ := systemctl.IsExist(clamServiceNameCentOs)
525-
if exist1 {
526-
isActive, _ = systemctl.IsActive(clamServiceNameCentOs)
527-
}
528-
exist2, _ := systemctl.IsExist(clamServiceNameUbuntu)
529-
if exist2 {
530-
isActive, _ = systemctl.IsActive(clamServiceNameUbuntu)
519+
isexist, _ := systemctl.IsExist(clamServiceKey)
520+
if isexist {
521+
isActive, _ = systemctl.IsActive(clamServiceKey)
531522
}
532523
if isActive {
533524
return false
@@ -590,42 +581,25 @@ func loadResultFromLog(pathItem string) dto.ClamLog {
590581
return data
591582
}
592583
func (c *ClamService) loadLogPath(name string) string {
593-
confPath := ""
594-
if name == "clamd-log" {
595-
if c.serviceName == clamServiceNameUbuntu {
596-
confPath = "/etc/clamav/clamd.conf"
597-
} else {
598-
confPath = "/etc/clamd.d/scan.conf"
599-
}
600-
} else {
601-
if c.serviceName == clamServiceNameUbuntu {
602-
confPath = "/etc/clamav/freshclam.conf"
603-
} else {
604-
confPath = "/etc/freshclam.conf"
605-
}
606-
}
607-
if _, err := os.Stat(confPath); err != nil {
608-
return ""
584+
configKey := "clamd"
585+
searchPrefix := "LogFile "
586+
if name != "clamd-log" {
587+
configKey = "freshclam"
588+
searchPrefix = "UpdateLogFile "
609589
}
590+
confPath := c.getConfigPath(configKey)
591+
610592
content, err := os.ReadFile(confPath)
611593
if err != nil {
594+
global.LOG.Debugf("Failed to read %s config: %v", configKey, err)
612595
return ""
613596
}
614-
lines := strings.Split(string(content), "\n")
615-
if name == "clamd-log" {
616-
for _, line := range lines {
617-
if strings.HasPrefix(line, "LogFile ") {
618-
return strings.Trim(strings.ReplaceAll(line, "LogFile ", ""), " ")
619-
}
620-
}
621-
} else {
622-
for _, line := range lines {
623-
if strings.HasPrefix(line, "UpdateLogFile ") {
624-
return strings.Trim(strings.ReplaceAll(line, "UpdateLogFile ", ""), " ")
625-
}
597+
598+
for _, line := range strings.Split(string(content), "\n") {
599+
if strings.HasPrefix(line, searchPrefix) {
600+
return strings.TrimSpace(strings.TrimPrefix(line, searchPrefix))
626601
}
627602
}
628-
629603
return ""
630604
}
631605

Diff for: backend/app/service/device.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
1919
"github.com/1Panel-dev/1Panel/backend/utils/common"
2020
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
21+
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
2122
"github.com/shirou/gopsutil/v3/mem"
2223
)
2324

@@ -121,7 +122,7 @@ func (u *DeviceService) Update(key, value string) error {
121122
return err
122123
}
123124
go func() {
124-
_, err := cmd.Exec("systemctl restart 1panel.service")
125+
err := systemctl.Restart("1panel")
125126
if err != nil {
126127
global.LOG.Errorf("restart system for new time zone failed, err: %v", err)
127128
}

Diff for: backend/app/service/device_clean.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ import (
1111

1212
"github.com/1Panel-dev/1Panel/backend/constant"
1313
"github.com/1Panel-dev/1Panel/backend/utils/docker"
14+
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
1415
"github.com/docker/docker/api/types"
1516
"github.com/docker/docker/api/types/filters"
1617

1718
"github.com/1Panel-dev/1Panel/backend/app/dto"
1819
"github.com/1Panel-dev/1Panel/backend/global"
19-
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
2020
"github.com/1Panel-dev/1Panel/backend/utils/common"
2121
fileUtils "github.com/1Panel-dev/1Panel/backend/utils/files"
2222
"github.com/google/uuid"
@@ -285,7 +285,7 @@ func (u *DeviceService) Clean(req []dto.Clean) {
285285

286286
if restart {
287287
go func() {
288-
_, err := cmd.Exec("systemctl restart 1panel.service")
288+
err := systemctl.Restart("1panel")
289289
if err != nil {
290290
global.LOG.Errorf("restart system port failed, err: %v", err)
291291
}

0 commit comments

Comments
 (0)