diff --git a/agent/app/service/ai.go b/agent/app/service/ai.go index c1fed9732..07d7912ff 100644 --- a/agent/app/service/ai.go +++ b/agent/app/service/ai.go @@ -134,9 +134,8 @@ func (u *AIToolService) Close(name string) error { if err != nil { return err } - stdout, err := cmd.RunDefaultWithStdoutBashCf("docker exec %s ollama stop %s", containerName, name) - if err != nil { - return fmt.Errorf("handle ollama stop %s failed, stdout: %s, err: %v", name, stdout, err) + if err := cmd.RunDefaultBashCf("docker exec %s ollama stop %s", containerName, name); err != nil { + return fmt.Errorf("handle ollama stop %s failed, %v", name, err) } return nil } @@ -193,9 +192,8 @@ func (u *AIToolService) Delete(req dto.ForceDelete) error { } for _, item := range ollamaList { if item.Status != constant.StatusDeleted { - stdout, err := cmd.RunDefaultWithStdoutBashCf("docker exec %s ollama rm %s", containerName, item.Name) - if err != nil && !req.ForceDelete { - return fmt.Errorf("handle ollama rm %s failed, stdout: %s, err: %v", item.Name, stdout, err) + if err := cmd.RunDefaultBashCf("docker exec %s ollama rm %s", containerName, item.Name); err != nil && !req.ForceDelete { + return fmt.Errorf("handle ollama rm %s failed, %v", item.Name, err) } } _ = aiRepo.Delete(repo.WithByID(item.ID)) diff --git a/agent/app/service/app_utils.go b/agent/app/service/app_utils.go index 78577d840..3bec11e24 100644 --- a/agent/app/service/app_utils.go +++ b/agent/app/service/app_utils.go @@ -1082,11 +1082,7 @@ func runScript(task *task.Task, appInstall *model.AppInstall, operate string) er task.LogStart(logStr) cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute), cmd.WithWorkDir(workDir)) - out, err := cmdMgr.RunWithStdoutBashC(scriptPath) - if err != nil { - if out != "" { - err = errors.New(out) - } + if err := cmdMgr.RunBashC(scriptPath); err != nil { task.LogFailedWithErr(logStr, err) return err } diff --git a/agent/app/service/backup_redis.go b/agent/app/service/backup_redis.go index 6e8b30938..713397607 100644 --- a/agent/app/service/backup_redis.go +++ b/agent/app/service/backup_redis.go @@ -19,7 +19,6 @@ import ( "github.com/1Panel-dev/1Panel/agent/utils/common" "github.com/1Panel-dev/1Panel/agent/utils/compose" "github.com/1Panel-dev/1Panel/agent/utils/files" - "github.com/pkg/errors" ) func (u *BackupService) RedisBackup(req dto.CommonBackup) error { @@ -98,9 +97,8 @@ func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, recordID } } - stdout, err := cmd.RunDefaultWithStdoutBashCf("docker exec %s redis-cli -a %s --no-auth-warning save", redisInfo.ContainerName, redisInfo.Password) - if err != nil { - return errors.New(string(stdout)) + if err := cmd.RunDefaultBashCf("docker exec %s redis-cli -a %s --no-auth-warning save", redisInfo.ContainerName, redisInfo.Password); err != nil { + return err } if strings.HasSuffix(fileName, ".tar.gz") { @@ -111,16 +109,14 @@ func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, recordID return nil } if strings.HasSuffix(fileName, ".aof") { - stdout1, err := cmd.RunDefaultWithStdoutBashCf("docker cp %s:/data/appendonly.aof %s/%s", redisInfo.ContainerName, backupDir, fileName) - if err != nil { - return errors.New(stdout1) + if err := cmd.RunDefaultBashCf("docker cp %s:/data/appendonly.aof %s/%s", redisInfo.ContainerName, backupDir, fileName); err != nil { + return err } return nil } - stdout1, err1 := cmd.RunDefaultWithStdoutBashCf("docker cp %s:/data/dump.rdb %s/%s", redisInfo.ContainerName, backupDir, fileName) - if err1 != nil { - return errors.New(stdout1) + if err := cmd.RunDefaultBashCf("docker cp %s:/data/dump.rdb %s/%s", redisInfo.ContainerName, backupDir, fileName); err != nil { + return err } return nil } diff --git a/agent/app/service/backup_website.go b/agent/app/service/backup_website.go index 1ccb01e54..c86e82263 100644 --- a/agent/app/service/backup_website.go +++ b/agent/app/service/backup_website.go @@ -16,7 +16,6 @@ import ( "github.com/1Panel-dev/1Panel/agent/i18n" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/compose" - "github.com/pkg/errors" "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/app/model" @@ -179,9 +178,8 @@ func handleWebsiteRecover(website *model.Website, parentTask *task.Task, recover if err = fileOp.TarGzExtractPro(fmt.Sprintf("%s/%s.web.tar.gz", tmpPath, website.Alias), GetOpenrestyDir(SitesRootDir), ""); err != nil { return err } - stdout, err := cmd.RunDefaultWithStdoutBashCf("docker exec -i %s nginx -s reload", nginxInfo.ContainerName) - if err != nil { - return errors.New(stdout) + if err := cmd.RunDefaultBashCf("docker exec -i %s nginx -s reload", nginxInfo.ContainerName); err != nil { + return err } oldWebsite.ID = website.ID if err := websiteRepo.SaveWithoutCtx(&oldWebsite); err != nil { diff --git a/agent/app/service/clam.go b/agent/app/service/clam.go index 823ca806f..614252860 100644 --- a/agent/app/service/clam.go +++ b/agent/app/service/clam.go @@ -21,14 +21,15 @@ import ( "github.com/1Panel-dev/1Panel/agent/utils/clam" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/common" - "github.com/1Panel-dev/1Panel/agent/utils/systemctl" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/1Panel-dev/1Panel/agent/utils/xpack" "github.com/jinzhu/copier" "github.com/robfig/cron/v3" ) type ClamService struct { - serviceName string + serviceName string + freshClamService string } type IClamService interface { @@ -56,23 +57,31 @@ func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) { var baseInfo dto.ClamBaseInfo baseInfo.Version = "-" baseInfo.FreshVersion = "-" - exist1, _ := systemctl.IsExist(constant.ClamServiceNameCentOs) - if exist1 { - c.serviceName = constant.ClamServiceNameCentOs - baseInfo.IsExist = true - baseInfo.IsActive, _ = systemctl.IsActive(constant.ClamServiceNameCentOs) + + clamSvc, err := controller.LoadServiceName("clam") + if err != nil { + baseInfo.IsExist = false + return baseInfo, nil } - exist2, _ := systemctl.IsExist(constant.ClamServiceNameUbuntu) - if exist2 { - c.serviceName = constant.ClamServiceNameUbuntu + c.serviceName = clamSvc + exist, _ := controller.CheckExist(clamSvc) + if exist { baseInfo.IsExist = true - baseInfo.IsActive, _ = systemctl.IsActive(constant.ClamServiceNameUbuntu) + baseInfo.IsActive, _ = controller.CheckActive(clamSvc) } - freshExist, _ := systemctl.IsExist(constant.FreshClamService) + + freshSvc, err := controller.LoadServiceName("freshclam") + if err != nil { + baseInfo.FreshIsExist = false + return baseInfo, nil + } + c.freshClamService = freshSvc + freshExist, _ := controller.CheckExist(freshSvc) if freshExist { baseInfo.FreshIsExist = true - baseInfo.FreshIsActive, _ = systemctl.IsActive(constant.FreshClamService) + baseInfo.FreshIsActive, _ = controller.CheckActive(freshSvc) } + if !cmd.Which("clamdscan") { baseInfo.IsActive = false } @@ -87,7 +96,7 @@ func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) { } } } else { - _ = clam.CheckClamIsActive(false, clamRepo) + _ = clam.StopAllClamJob(false, clamRepo) } if baseInfo.FreshIsActive { version, err := cmd.RunDefaultWithStdoutBashC("freshclam --version") @@ -105,15 +114,13 @@ func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) { func (c *ClamService) Operate(operate string) error { switch operate { case "start", "restart", "stop": - stdout, err := cmd.RunDefaultWithStdoutBashCf("systemctl %s %s", operate, c.serviceName) - if err != nil { - return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, stdout) + if err := controller.Handle(operate, c.serviceName); err != nil { + return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, err) } return nil case "fresh-start", "fresh-restart", "fresh-stop": - stdout, err := cmd.RunDefaultWithStdoutBashCf("systemctl %s %s", strings.TrimPrefix(operate, "fresh-"), constant.FreshClamService) - if err != nil { - return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, stdout) + if err := controller.Handle(strings.TrimPrefix(operate, "fresh-"), c.freshClamService); err != nil { + return fmt.Errorf("%s the %s failed, err: %s", operate, c.serviceName, err) } return nil default: @@ -306,7 +313,7 @@ func (c *ClamService) Delete(req dto.ClamDelete) error { } func (c *ClamService) HandleOnce(id uint) error { - if active := clam.CheckClamIsActive(true, clamRepo); !active { + if active := clam.StopAllClamJob(true, clamRepo); !active { return buserr.New("ErrClamdscanNotFound") } clamItem, _ := clamRepo.Get(repo.WithByID(id)) @@ -379,37 +386,13 @@ func (c *ClamService) LoadFile(req dto.ClamFileReq) (string, error) { filePath := "" switch req.Name { case "clamd": - if c.serviceName == constant.ClamServiceNameUbuntu { - filePath = "/etc/clamav/clamd.conf" - } else { - filePath = "/etc/clamd.d/scan.conf" - } + filePath = c.loadConfigPath("clamd") case "clamd-log": filePath = c.loadLogPath("clamd-log") - if len(filePath) != 0 { - break - } - if c.serviceName == constant.ClamServiceNameUbuntu { - filePath = "/var/log/clamav/clamav.log" - } else { - filePath = "/var/log/clamd.scan" - } case "freshclam": - if c.serviceName == constant.ClamServiceNameUbuntu { - filePath = "/etc/clamav/freshclam.conf" - } else { - filePath = "/etc/freshclam.conf" - } + filePath = c.loadConfigPath("freshclam") case "freshclam-log": filePath = c.loadLogPath("freshclam-log") - if len(filePath) != 0 { - break - } - if c.serviceName == constant.ClamServiceNameUbuntu { - filePath = "/var/log/clamav/freshclam.log" - } else { - filePath = "/var/log/freshclam.log" - } default: return "", fmt.Errorf("not support such type") } @@ -432,23 +415,11 @@ func (c *ClamService) LoadFile(req dto.ClamFileReq) (string, error) { func (c *ClamService) UpdateFile(req dto.UpdateByNameAndFile) error { filePath := "" - service := "" switch req.Name { case "clamd": - if c.serviceName == constant.ClamServiceNameUbuntu { - service = constant.ClamServiceNameUbuntu - filePath = "/etc/clamav/clamd.conf" - } else { - service = constant.ClamServiceNameCentOs - filePath = "/etc/clamd.d/scan.conf" - } + filePath = c.loadConfigPath("clamd") case "freshclam": - if c.serviceName == constant.ClamServiceNameUbuntu { - filePath = "/etc/clamav/freshclam.conf" - } else { - filePath = "/etc/freshclam.conf" - } - service = "clamav-freshclam.service" + filePath = c.loadConfigPath("freshclam") default: return fmt.Errorf("not support such type") } @@ -461,50 +432,65 @@ func (c *ClamService) UpdateFile(req dto.UpdateByNameAndFile) error { _, _ = write.WriteString(req.File) write.Flush() - _ = systemctl.Restart(service) + _ = controller.HandleRestart(c.serviceName) return nil } func (c *ClamService) loadLogPath(name string) string { - confPath := "" - if name == "clamd-log" { - if c.serviceName == constant.ClamServiceNameUbuntu { - confPath = "/etc/clamav/clamd.conf" - } else { - confPath = "/etc/clamd.d/scan.conf" - } - } else { - if c.serviceName == constant.ClamServiceNameUbuntu { - confPath = "/etc/clamav/freshclam.conf" - } else { - confPath = "/etc/freshclam.conf" - } - } - if _, err := os.Stat(confPath); err != nil { - return "" + configKey := "clamd" + searchPrefix := "LogFile " + if name != "clamd-log" { + configKey = "freshclam" + searchPrefix = "UpdateLogFile " } + confPath := c.loadConfigPath(configKey) content, err := os.ReadFile(confPath) if err != nil { + global.LOG.Debugf("read config of %s failed, err: %v", configKey, err) return "" } lines := strings.Split(string(content), "\n") - if name == "clamd-log" { - for _, line := range lines { - if strings.HasPrefix(line, "LogFile ") { - return strings.Trim(strings.ReplaceAll(line, "LogFile ", ""), " ") - } - } - } else { - for _, line := range lines { - if strings.HasPrefix(line, "UpdateLogFile ") { - return strings.Trim(strings.ReplaceAll(line, "UpdateLogFile ", ""), " ") - } + for _, line := range lines { + if strings.HasPrefix(line, searchPrefix) { + return strings.Trim(strings.ReplaceAll(line, searchPrefix, ""), " ") + } + } + if configKey == "clamd" { + if _, err := os.Stat("/var/log/clamav/clamav.log"); err == nil { + return "/var/log/clamav/clamav.log" + } + if _, err := os.Stat("/var/log/clamd.scan"); err == nil { + return "/var/log/clamd.scan" + } + } + if configKey == "freshclam" { + if _, err := os.Stat("/var/log/clamav/freshclam.log"); err == nil { + return "/var/log/clamav/freshclam.log" + } + if _, err := os.Stat("/var/log/freshclam.log"); err == nil { + return "/var/log/freshclam.log" } } - return "" } +func (c *ClamService) loadConfigPath(confType string) string { + switch confType { + case "clamd": + if _, err := os.Stat("/etc/clamav/clamd.conf"); err == nil { + return "/etc/clamav/clamd.conf" + } + return "/etc/clamd.d/scan.conf" + case "freshclam": + if _, err := os.Stat("/etc/clamav/freshclam.conf"); err == nil { + return "/etc/clamav/freshclam.conf" + } + return "/etc/freshclam.conf" + default: + return "" + } +} + func handleAlert(infectedFiles, clamName string, clamId uint) { itemInfected, _ := strconv.Atoi(strings.TrimSpace(infectedFiles)) if itemInfected < 0 { diff --git a/agent/app/service/dashboard.go b/agent/app/service/dashboard.go index ed7c2d392..6e293bcc6 100644 --- a/agent/app/service/dashboard.go +++ b/agent/app/service/dashboard.go @@ -21,6 +21,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/utils/ai_tools/xpu" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/common" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/1Panel-dev/1Panel/agent/utils/copier" "github.com/gin-gonic/gin" "github.com/shirou/gopsutil/v4/cpu" @@ -53,23 +54,25 @@ func NewIDashboardService() IDashboardService { } func (u *DashboardService) Restart(operation string) error { - if operation != "1panel" && operation != "system" && operation != "1panel-agent" { + switch operation { + case "system": + { + go func() { + if err := cmd.RunDefaultBashCf("%s reboot", cmd.SudoHandleCmd()); err != nil { + global.LOG.Errorf("handle reboot failed, %v", err) + } + }() + return nil + } + case "1panel-agent": + controller.RestartPanel(false, true, false) + return nil + case "1panel": + controller.RestartPanel(true, true, false) + return nil + default: return fmt.Errorf("handle restart operation %s failed, err: nonsupport such operation", operation) } - itemCmd := fmt.Sprintf("%s systemctl restart 1panel-agent.service && %s systemctl restart 1panel-core.service", cmd.SudoHandleCmd(), cmd.SudoHandleCmd()) - if operation == "system" { - itemCmd = fmt.Sprintf("%s reboot", cmd.SudoHandleCmd()) - } - if operation == "1panel-agent" { - itemCmd = fmt.Sprintf("%s systemctl restart 1panel-agent.service", cmd.SudoHandleCmd()) - } - go func() { - stdout, err := cmd.RunDefaultWithStdoutBashC(itemCmd) - if err != nil { - global.LOG.Errorf("handle %s failed, err: %v", itemCmd, stdout) - } - }() - return nil } func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) { diff --git a/agent/app/service/device.go b/agent/app/service/device.go index 2fbeef8f4..efd42d674 100644 --- a/agent/app/service/device.go +++ b/agent/app/service/device.go @@ -2,7 +2,6 @@ package service import ( "bufio" - "errors" "fmt" "net" "os" @@ -19,6 +18,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/i18n" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/common" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/1Panel-dev/1Panel/agent/utils/ntp" "github.com/shirou/gopsutil/v4/mem" ) @@ -122,7 +122,7 @@ func (u *DeviceService) Update(key, value string) error { if err := ntp.UpdateSystemTimeZone(value); err != nil { return err } - go common.RestartService(global.IsMaster, true, false) + go controller.RestartPanel(global.IsMaster, true, false) case "DNS": if err := updateDNS(strings.Split(value, ",")); err != nil { return err @@ -131,9 +131,8 @@ func (u *DeviceService) Update(key, value string) error { if cmd.CheckIllegal(value) { return buserr.New("ErrCmdIllegal") } - std, err := cmd.RunDefaultWithStdoutBashCf("%s hostnamectl set-hostname %s", cmd.SudoHandleCmd(), value) - if err != nil { - return errors.New(std) + if err := cmd.RunDefaultBashCf("%s hostnamectl set-hostname %s", cmd.SudoHandleCmd(), value); err != nil { + return err } case "Ntp", "LocalTime": if cmd.CheckIllegal(value) { @@ -222,12 +221,11 @@ func (u *DeviceService) UpdatePasswd(req dto.ChangePasswd) error { if cmd.CheckIllegal(req.User, req.Passwd) { return buserr.New("ErrCmdIllegal") } - std, err := cmd.RunDefaultWithStdoutBashCf("%s echo '%s:%s' | %s chpasswd", cmd.SudoHandleCmd(), req.User, req.Passwd, cmd.SudoHandleCmd()) - if err != nil { + if err := cmd.RunDefaultBashCf("%s echo '%s:%s' | %s chpasswd", cmd.SudoHandleCmd(), req.User, req.Passwd, cmd.SudoHandleCmd()); err != nil { if strings.Contains(err.Error(), "does not exist") { return buserr.New("ErrNotExistUser") } - return errors.New(std) + return err } return nil } @@ -245,9 +243,8 @@ func (u *DeviceService) UpdateSwap(req dto.SwapHelper) error { } cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*taskItem)) if !req.IsNew { - std, err := cmdMgr.RunWithStdoutBashCf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path) - if err != nil { - return fmt.Errorf("handle swapoff %s failed, err: %s", req.Path, std) + if err := cmdMgr.RunBashCf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path); err != nil { + return fmt.Errorf("handle swapoff %s failed, %v", req.Path) } } if req.Size == 0 { @@ -257,27 +254,23 @@ func (u *DeviceService) UpdateSwap(req dto.SwapHelper) error { return operateSwapWithFile(true, req) } taskItem.LogStart(i18n.GetMsgByKey("CreateSwap")) - stdDD, err := cmdMgr.RunWithStdoutBashCf("%s dd if=/dev/zero of=%s bs=1024 count=%d", cmd.SudoHandleCmd(), req.Path, req.Size) - if err != nil { - return fmt.Errorf("handle dd %s failed, std: %s, err: %s", req.Path, stdDD, err) + if err := cmdMgr.RunBashCf("%s dd if=/dev/zero of=%s bs=1024 count=%d", cmd.SudoHandleCmd(), req.Path, req.Size); err != nil { + return fmt.Errorf("handle dd %s failed, %v", req.Path, err) } taskItem.Log("chmod 0600 " + req.Path) - stdChmod, err := cmdMgr.RunWithStdoutBashCf("%s chmod 0600 %s", cmd.SudoHandleCmd(), req.Path) - if err != nil { - return fmt.Errorf("handle chmod 0600 %s failed,std: %s, err: %s", req.Path, stdChmod, err) + if err := cmdMgr.RunBashCf("%s chmod 0600 %s", cmd.SudoHandleCmd(), req.Path); err != nil { + return fmt.Errorf("handle chmod 0600 %s failed, %v", req.Path, err) } taskItem.LogStart(i18n.GetMsgByKey("FormatSwap")) - stdMkswap, err := cmdMgr.RunWithStdoutBashCf("%s mkswap -f %s", cmd.SudoHandleCmd(), req.Path) - if err != nil { - return fmt.Errorf("handle mkswap -f %s failed, std: %s, err: %s", req.Path, stdMkswap, err) + if err := cmdMgr.RunBashCf("%s mkswap -f %s", cmd.SudoHandleCmd(), req.Path); err != nil { + return fmt.Errorf("handle mkswap -f %s failed, %v", req.Path, err) } taskItem.LogStart(i18n.GetMsgByKey("EnableSwap")) - stdSwapon, err := cmdMgr.RunWithStdoutBashCf("%s swapon %s", cmd.SudoHandleCmd(), req.Path) - if err != nil { - _, _ = cmdMgr.RunWithStdoutBashCf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path) - return fmt.Errorf("handle swapoff %s failed,std: %s, err: %s", req.Path, stdSwapon, err) + if err := cmdMgr.RunBashCf("%s swapon %s", cmd.SudoHandleCmd(), req.Path); err != nil { + _ = cmdMgr.RunBashCf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path) + return fmt.Errorf("handle swapoff %s failed, %v", req.Path, err) } return operateSwapWithFile(false, req) }, nil) diff --git a/agent/app/service/device_clean.go b/agent/app/service/device_clean.go index 67e41ea92..5656ca92d 100644 --- a/agent/app/service/device_clean.go +++ b/agent/app/service/device_clean.go @@ -13,6 +13,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/i18n" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/1Panel-dev/1Panel/agent/utils/docker" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/build" @@ -260,7 +261,7 @@ func (u *DeviceService) Clean(req []dto.Clean) { _ = settingRepo.Update("LastCleanData", fmt.Sprintf("%v", len(req))) if restart { - go common.RestartService(false, true, false) + go controller.RestartPanel(false, true, false) } } diff --git a/agent/app/service/docker.go b/agent/app/service/docker.go index 865b24ed7..78952d547 100644 --- a/agent/app/service/docker.go +++ b/agent/app/service/docker.go @@ -8,15 +8,13 @@ import ( "os" "path" "strings" - "time" "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/1Panel-dev/1Panel/agent/utils/docker" - "github.com/1Panel-dev/1Panel/agent/utils/systemctl" - "github.com/pkg/errors" ) type DockerService struct{} @@ -236,7 +234,9 @@ func (u *DockerService) UpdateConf(req dto.SettingUpdate, withRestart bool) erro } if withRestart { - return restartDocker() + if err := controller.HandleRestart("docker"); err != nil { + return fmt.Errorf("failed to restart Docker: %v", err) + } } return nil } @@ -280,8 +280,8 @@ func (u *DockerService) UpdateLogOption(req dto.LogOption) error { return err } - if err := restartDocker(); err != nil { - return err + if err := controller.HandleRestart("docker"); err != nil { + return fmt.Errorf("failed to restart Docker: %v", err) } return nil } @@ -319,8 +319,8 @@ func (u *DockerService) UpdateIpv6Option(req dto.Ipv6Option) error { return err } - if err := restartDocker(); err != nil { - return err + if err := controller.HandleRestart("docker"); err != nil { + return fmt.Errorf("failed to restart Docker: %v", err) } return nil } @@ -343,25 +343,19 @@ func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error { return err } - if err := restartDocker(); err != nil { - return err + if err := controller.HandleRestart("docker"); err != nil { + return fmt.Errorf("failed to restart Docker: %v", err) } return nil } func (u *DockerService) OperateDocker(req dto.DockerOperation) error { service := "docker" - sudo := cmd.SudoHandleCmd() - dockerCmd, err := getDockerRestartCommand() - if err != nil { - return err - } if req.Operation == "stop" { - isSocketActive, _ := systemctl.IsActive("docker.socket") + isSocketActive, _ := controller.CheckExist("docker.socket") if isSocketActive { - std, err := cmd.RunDefaultWithStdoutBashCf("%s systemctl stop docker.socket", sudo) - if err != nil { - global.LOG.Errorf("handle systemctl stop docker.socket failed, err: %v", std) + if err := controller.HandleStop("docker.socket"); err != nil { + global.LOG.Errorf("handle stop docker.socket failed, err: %v", err) } } } @@ -370,9 +364,8 @@ func (u *DockerService) OperateDocker(req dto.DockerOperation) error { return err } } - stdout, err := cmd.RunDefaultWithStdoutBashCf("%s %s %s ", dockerCmd, req.Operation, service) - if err != nil { - return errors.New(string(stdout)) + if err := controller.Handle(req.Operation, service); err != nil { + return err } return nil } @@ -435,32 +428,7 @@ func validateDockerConfig() error { return nil } if err != nil || (stdout != "" && strings.TrimSpace(stdout) != "configuration OK") { - return fmt.Errorf("Docker configuration validation failed, err: %v", stdout) - } - return nil -} - -func getDockerRestartCommand() (string, error) { - stdout, err := cmd.RunDefaultWithStdoutBashC("which docker") - if err != nil { - return "", fmt.Errorf("failed to find docker: %v", err) - } - dockerPath := stdout - if strings.Contains(dockerPath, "snap") { - return "snap", nil - } - return "systemctl", nil -} - -func restartDocker() error { - global.LOG.Info("restart docker") - restartCmd, err := getDockerRestartCommand() - if err != nil { - return err - } - stdout, err := cmd.NewCommandMgr(cmd.WithTimeout(3*time.Minute)).RunWithStdoutBashCf("%s restart docker", restartCmd) - if err != nil { - return fmt.Errorf("failed to restart Docker: %s", stdout) + return fmt.Errorf("Docker configuration validation failed, %v", err) } return nil } diff --git a/agent/app/service/firewall.go b/agent/app/service/firewall.go index 0bd48b33b..679cc2377 100644 --- a/agent/app/service/firewall.go +++ b/agent/app/service/firewall.go @@ -16,6 +16,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/common" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/1Panel-dev/1Panel/agent/utils/firewall" fireClient "github.com/1Panel-dev/1Panel/agent/utils/firewall/client" "github.com/jinzhu/copier" @@ -211,8 +212,8 @@ func (u *FirewallService) OperateFirewall(req dto.FirewallOperation) error { return fmt.Errorf("not supported operation: %s", req.Operation) } if needRestartDocker && req.WithDockerRestart { - if err := restartDocker(); err != nil { - return err + if err := controller.HandleRestart("docker"); err != nil { + return fmt.Errorf("failed to restart Docker: %v", err) } } return nil @@ -624,9 +625,8 @@ func (u *FirewallService) updatePingStatus(enable string) error { return err } - stdout, err := cmd.RunDefaultWithStdoutBashCf("%s sysctl -p", cmd.SudoHandleCmd()) - if err != nil { - return fmt.Errorf("update ping status failed, err: %v", stdout) + if err := cmd.RunDefaultBashCf("%s sysctl -p", cmd.SudoHandleCmd()); err != nil { + return fmt.Errorf("update ping status failed, %v", err) } return nil diff --git a/agent/app/service/host_tool.go b/agent/app/service/host_tool.go index 2e5fa1cf6..d9ba89623 100644 --- a/agent/app/service/host_tool.go +++ b/agent/app/service/host_tool.go @@ -17,9 +17,9 @@ import ( "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/1Panel-dev/1Panel/agent/utils/files" "github.com/1Panel-dev/1Panel/agent/utils/ini_conf" - "github.com/1Panel-dev/1Panel/agent/utils/systemctl" "github.com/pkg/errors" "gopkg.in/ini.v1" ) @@ -52,9 +52,9 @@ func (h *HostToolService) GetToolStatus(req request.HostToolReq) (*response.Host return res, nil } supervisorConfig.IsExist = true - serviceExist, _ := systemctl.IsExist(constant.Supervisord) + serviceExist, _ := controller.CheckExist(constant.Supervisord) if !serviceExist { - serviceExist, _ = systemctl.IsExist(constant.Supervisor) + serviceExist, _ = controller.CheckExist(constant.Supervisor) if !serviceExist { supervisorConfig.IsExist = false res.Config = supervisorConfig @@ -76,7 +76,7 @@ func (h *HostToolService) GetToolStatus(req request.HostToolReq) (*response.Host _, ctlRrr := exec.LookPath("supervisorctl") supervisorConfig.CtlExist = ctlRrr == nil - active, _ := systemctl.IsActive(supervisorConfig.ServiceName) + active, _ := controller.CheckActive(supervisorConfig.ServiceName) if active { supervisorConfig.Status = "running" } else { @@ -193,7 +193,7 @@ func (h *HostToolService) CreateToolConfig(req request.HostToolCreate) error { return err } } - if err = systemctl.Restart(req.ServiceName); err != nil { + if err = controller.HandleRestart(req.ServiceName); err != nil { global.LOG.Errorf("[init] restart %s failed err %s", req.ServiceName, err.Error()) return err } @@ -209,7 +209,7 @@ func (h *HostToolService) OperateTool(req request.HostToolReq) error { serviceName = serviceNameSet.Value } } - return systemctl.Operate(req.Operate, serviceName) + return controller.Handle(req.Operate, serviceName) } func (h *HostToolService) OperateToolConfig(req request.HostToolConfig) (*response.HostToolConfig, error) { @@ -251,7 +251,7 @@ func (h *HostToolService) OperateToolConfig(req request.HostToolConfig) (*respon if err = fileOp.WriteFile(configPath, strings.NewReader(req.Content), fileInfo.Mode()); err != nil { return nil, err } - if err = systemctl.Restart(serviceName); err != nil { + if err = controller.HandleRestart(serviceName); err != nil { _ = fileOp.WriteFile(configPath, bytes.NewReader(oldContent), fileInfo.Mode()) return nil, err } diff --git a/agent/app/service/image_repo.go b/agent/app/service/image_repo.go index 3b4950132..8e050a3d1 100644 --- a/agent/app/service/image_repo.go +++ b/agent/app/service/image_repo.go @@ -16,6 +16,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/common" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/jinzhu/copier" "github.com/pkg/errors" ) @@ -134,7 +135,7 @@ func (u *ImageRepoService) Delete(req dto.OperateByID) error { return err } go func() { - _ = restartDocker() + _ = controller.HandleRestart("docker") }() return nil } @@ -262,8 +263,8 @@ func stopBeforeUpdateRepo() error { if err := validateDockerConfig(); err != nil { return err } - if err := restartDocker(); err != nil { - return err + if err := controller.HandleRestart("docker"); err != nil { + return fmt.Errorf("failed to restart Docker: %v", err) } ticker := time.NewTicker(3 * time.Second) defer ticker.Stop() @@ -275,8 +276,8 @@ func stopBeforeUpdateRepo() error { cancel() return errors.New("the docker service cannot be restarted") default: - stdout, err := cmd.RunDefaultWithStdoutBashC("systemctl is-active docker") - if string(stdout) == "active\n" && err == nil { + active, err := controller.CheckActive("docker") + if active && err != nil { global.LOG.Info("docker restart with new conf successful!") return nil } diff --git a/agent/app/service/nginx_utils.go b/agent/app/service/nginx_utils.go index 62b39fc93..ebb661149 100644 --- a/agent/app/service/nginx_utils.go +++ b/agent/app/service/nginx_utils.go @@ -1,7 +1,6 @@ package service import ( - "errors" "fmt" "os" "path" @@ -238,10 +237,6 @@ func getNginxParamsFromStaticFile(scope dto.NginxKey, newParams []dto.NginxParam } func opNginx(containerName, operate string) error { - var ( - out string - err error - ) cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(20 * time.Second)) cmdStr := fmt.Sprintf("docker exec -i %s nginx ", containerName) if operate == constant.NginxCheck { @@ -249,11 +244,7 @@ func opNginx(containerName, operate string) error { } else { cmdStr = cmdStr + "-s reload" } - out, err = cmdMgr.RunWithStdoutBashC(cmdStr) - if err != nil { - if out != "" { - return errors.New(out) - } + if err := cmdMgr.RunBashC(cmdStr); err != nil { return err } return nil diff --git a/agent/app/service/runtime.go b/agent/app/service/runtime.go index 7f647543e..27f08bc31 100644 --- a/agent/app/service/runtime.go +++ b/agent/app/service/runtime.go @@ -5,7 +5,6 @@ import ( "context" "encoding/json" "fmt" - fcgiclient "github.com/tomasen/fcgi_client" "maps" "os" "os/exec" @@ -17,6 +16,8 @@ import ( "strings" "time" + fcgiclient "github.com/tomasen/fcgi_client" + "github.com/1Panel-dev/1Panel/agent/app/task" "github.com/1Panel-dev/1Panel/agent/cmd/server/nginx_conf" "gopkg.in/ini.v1" @@ -679,9 +680,6 @@ func (r *RuntimeService) GetPHPExtensions(runtimeID uint) (response.PHPExtension cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(20 * time.Second)) out, err := cmdMgr.RunWithStdoutBashCf("docker exec -i %s php -m", runtime.ContainerName) if err != nil { - if out != "" { - return res, errors.New(out) - } return res, err } extensions := strings.Split(out, "\n") diff --git a/agent/app/service/snapshot_create.go b/agent/app/service/snapshot_create.go index 8e5838110..2c335f7bf 100644 --- a/agent/app/service/snapshot_create.go +++ b/agent/app/service/snapshot_create.go @@ -23,7 +23,6 @@ import ( "github.com/1Panel-dev/1Panel/agent/utils/common" "github.com/1Panel-dev/1Panel/agent/utils/copier" "github.com/1Panel-dev/1Panel/agent/utils/files" - "github.com/pkg/errors" "gorm.io/gorm" ) @@ -381,10 +380,9 @@ func snapAppImage(snap snapHelper, req dto.SnapshotCreate, targetDir string) err if len(imageList) != 0 { snap.Task.Log(strings.Join(imageList, " ")) snap.Task.Logf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz")) - std, err := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute)).RunWithStdoutBashCf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz")) - if err != nil { - snap.Task.LogFailedWithErr(i18n.GetMsgByKey("SnapDockerSave"), errors.New(std)) - return errors.New(std) + if err := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute)).RunBashCf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz")); err != nil { + snap.Task.LogFailedWithErr(i18n.GetMsgByKey("SnapDockerSave"), err) + return err } snap.Task.LogSuccess(i18n.GetMsgByKey("SnapDockerSave")) } else { diff --git a/agent/app/service/snapshot_recover.go b/agent/app/service/snapshot_recover.go index e18a108e1..ca92cd6c0 100644 --- a/agent/app/service/snapshot_recover.go +++ b/agent/app/service/snapshot_recover.go @@ -17,7 +17,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/i18n" "github.com/1Panel-dev/1Panel/agent/utils/cmd" - "github.com/1Panel-dev/1Panel/agent/utils/common" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/1Panel-dev/1Panel/agent/utils/files" "github.com/pkg/errors" ) @@ -226,7 +226,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error { return } _ = os.RemoveAll(rootDir) - common.RestartService(true, true, true) + controller.RestartPanel(true, true, true) }() return nil } @@ -352,10 +352,9 @@ func recoverAppData(src string, itemHelper *snapRecoverHelper) error { itemHelper.Task.Log(i18n.GetMsgByKey("RecoverAppEmpty")) return nil } - std, err := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute)).RunWithStdoutBashCf("docker load < %s", path.Join(src, "images.tar.gz")) - if err != nil { - itemHelper.Task.LogFailedWithErr(i18n.GetMsgByKey("RecoverAppImage"), errors.New(std)) - return fmt.Errorf("docker load images failed, err: %v", err) + if err := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute)).RunBashCf("docker load < %s", path.Join(src, "images.tar.gz")); err != nil { + itemHelper.Task.LogFailedWithErr(i18n.GetMsgByKey("RecoverAppImage"), err) + return fmt.Errorf("docker load images failed, %v", err) } itemHelper.Task.LogSuccess(i18n.GetMsgByKey("RecoverAppImage")) return nil @@ -404,8 +403,8 @@ func recoverBaseData(src string, itemHelper *snapRecoverHelper) error { } } - if err := restartDocker(); err != nil { - return err + if err := controller.HandleRestart("docker"); err != nil { + return fmt.Errorf("failed to restart Docker: %v", err) } return nil } @@ -435,9 +434,8 @@ func restartCompose(composePath string, itemHelper *snapRecoverHelper) error { continue } upCmd := fmt.Sprintf("docker compose -f %s up -d", pathItem) - stdout, err := cmd.RunDefaultWithStdoutBashC(upCmd) - if err != nil { - itemHelper.Task.LogFailedWithErr(i18n.GetMsgByKey("RecoverCompose"), errors.New(stdout)) + if err := cmd.RunDefaultBashC(upCmd); err != nil { + itemHelper.Task.LogFailedWithErr(i18n.GetMsgByKey("RecoverCompose"), err) continue } itemHelper.Task.LogSuccess(i18n.GetWithName("RecoverComposeItem", pathItem)) diff --git a/agent/app/service/ssh.go b/agent/app/service/ssh.go index 181737c2d..7a10de178 100644 --- a/agent/app/service/ssh.go +++ b/agent/app/service/ssh.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "net" "os" "os/user" "path" @@ -13,6 +14,7 @@ import ( "strings" "time" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/1Panel-dev/1Panel/agent/utils/copier" csvexport "github.com/1Panel-dev/1Panel/agent/utils/csv_export" "github.com/1Panel-dev/1Panel/agent/utils/encrypt" @@ -27,7 +29,6 @@ import ( "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/common" - "github.com/1Panel-dev/1Panel/agent/utils/systemctl" "github.com/pkg/errors" ) @@ -74,22 +75,18 @@ func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) { data.IsExist = false data.Message = err.Error() } else { - active, err := systemctl.IsActive(serviceName) + active, err := controller.CheckActive(serviceName) data.IsActive = active if !active && err != nil { data.Message = err.Error() } } - out, err := systemctl.RunSystemCtl("is-enabled", serviceName) + enable, err := controller.CheckEnable(serviceName) if err != nil { data.AutoStart = false } else { - if out == "alias\n" { - data.AutoStart, _ = systemctl.IsEnable("ssh") - } else { - data.AutoStart = out == "enabled\n" - } + data.AutoStart = enable } sshConf, err := os.ReadFile(sshPath) @@ -139,29 +136,20 @@ func (u *SSHService) OperateSSH(operation string) error { if err != nil { return err } - sudo := cmd.SudoHandleCmd() if operation == "enable" || operation == "disable" { serviceName += ".service" } if operation == "stop" { - isSocketActive, _ := systemctl.IsActive(serviceName + ".socket") + isSocketActive, _ := controller.CheckActive(serviceName + ".socket") if isSocketActive { - std, err := cmd.RunDefaultWithStdoutBashCf("%s systemctl stop %s", sudo, serviceName+".socket") - if err != nil { - global.LOG.Errorf("handle systemctl stop %s.socket failed, err: %v", serviceName, std) + if err := controller.HandleStop(serviceName + ".socket"); err != nil { + global.LOG.Errorf("handle stop %s.socket failed, err: %v", serviceName, err) } } } - stdout, err := cmd.RunDefaultWithStdoutBashCf("%s systemctl %s %s", sudo, operation, serviceName) - if err != nil { - if strings.Contains(stdout, "alias name or linked unit file") { - stdout, err := cmd.RunDefaultWithStdoutBashCf("%s systemctl %s ssh", sudo, operation) - if err != nil { - return fmt.Errorf("%s ssh(alias name or linked unit file) failed, stdout: %s, err: %v", operation, stdout, err) - } - } - return fmt.Errorf("%s %s failed, stdout: %s, err: %v", operation, serviceName, stdout, err) + if err := controller.Handle(operation, serviceName); err != nil { + return fmt.Errorf("%s %s failed, err: %v", operation, serviceName, err) } return nil } @@ -190,7 +178,7 @@ func (u *SSHService) Update(req dto.SSHUpdate) error { if req.Key == "Port" { stdout, _ := cmd.RunDefaultWithStdoutBashCf("%s getenforce", sudo) if stdout == "Enforcing\n" { - _, _ = cmd.RunDefaultWithStdoutBashCf("%s semanage port -a -t ssh_port_t -p tcp %s", sudo, req.NewValue) + _ = cmd.RunDefaultBashCf("%s semanage port -a -t ssh_port_t -p tcp %s", sudo, req.NewValue) } ruleItem := dto.PortRuleUpdate{ @@ -220,7 +208,7 @@ func (u *SSHService) Update(req dto.SSHUpdate) error { } } - _, _ = cmd.RunDefaultWithStdoutBashCf("%s systemctl restart %s", sudo, serviceName) + _ = controller.HandleRestart(serviceName) return nil } @@ -306,15 +294,13 @@ func (u *SSHService) CreateRootCert(req dto.RootCertOperate) error { if len(req.PassPhrase) != 0 { command = fmt.Sprintf("ssh-keygen -t %s -P %s -f %s/.ssh/%s | echo y", req.EncryptionMode, req.PassPhrase, currentUser.HomeDir, req.Name) } - stdout, err := cmd.RunDefaultWithStdoutBashC(command) - if err != nil { - return fmt.Errorf("generate failed, err: %v, message: %s", err, stdout) + if err := cmd.RunDefaultBashC(command); err != nil { + return fmt.Errorf("generate failed, %v", err) } } - stdout, err := cmd.RunDefaultWithStdoutBashCf("cat %s >> %s", publicPath, authFilePath) - if err != nil { - return fmt.Errorf("generate failed, err: %v, message: %s", err, stdout) + if err := cmd.RunDefaultBashCf("cat %s >> %s", publicPath, authFilePath); err != nil { + return fmt.Errorf("generate failed, %v", err) } cert.PrivateKeyPath = privatePath @@ -599,8 +585,7 @@ func (u *SSHService) UpdateByFile(req dto.SettingUpdate) error { if err != nil { return err } - sudo := cmd.SudoHandleCmd() - _, _ = cmd.RunDefaultWithStdoutBashCf("%s systemctl restart %s", sudo, serviceName) + _ = controller.HandleRestart(serviceName) return nil } @@ -772,24 +757,24 @@ func loadFailedSecureDatas(line string) dto.SSHHistory { } func checkIsStandard(item dto.SSHHistory) bool { - if len(item.Address) == 0 { + if len(item.Address) == 0 || net.ParseIP(item.Address) == nil { return false } portItem, _ := strconv.Atoi(item.Port) - return portItem != 0 + return portItem > 0 && portItem < 65536 } func handleGunzip(path string) error { - if _, err := cmd.RunDefaultWithStdoutBashCf("gunzip %s", path); err != nil { + if err := cmd.RunDefaultBashCf("gunzip %s", path); err != nil { return err } return nil } func loadServiceName() (string, error) { - if exist, _ := systemctl.IsExist("sshd"); exist { + if exist, _ := controller.CheckExist("sshd"); exist { return "sshd", nil - } else if exist, _ := systemctl.IsExist("ssh"); exist { + } else if exist, _ := controller.CheckExist("ssh"); exist { return "ssh", nil } return "", errors.New("The ssh or sshd service is unavailable") @@ -867,7 +852,7 @@ func updateLocalConn(newPort uint) error { } func updateSSHSocketFile(newPort string) error { - active, _ := systemctl.IsActive("ssh.socket") + active, _ := controller.CheckActive("ssh.socket") if !active { return nil } @@ -898,6 +883,7 @@ func updateSSHSocketFile(newPort string) error { if _, err = fileItem.WriteString(strings.Join(lines, "\n")); err != nil { return err } - _ = cmd.RunDefaultBashC("systemctl daemon-reload && systemctl restart ssh.socket") + _ = controller.Reload() + _ = controller.HandleRestart("ssh.socket") return nil } diff --git a/agent/app/service/website.go b/agent/app/service/website.go index 9e6521246..d6c79515c 100644 --- a/agent/app/service/website.go +++ b/agent/app/service/website.go @@ -1632,10 +1632,7 @@ func (w WebsiteService) UpdateSitePermission(req request.WebsiteUpdateDirPermiss } absoluteIndexPath := GetSitePath(website, SiteIndexDir) cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(10 * time.Second)) - if out, err := cmdMgr.RunWithStdoutBashCf("%s chown -R %s:%s %s", cmd.SudoHandleCmd(), req.User, req.Group, absoluteIndexPath); err != nil { - if out != "" { - return errors.New(out) - } + if err := cmdMgr.RunBashCf("%s chown -R %s:%s %s", cmd.SudoHandleCmd(), req.User, req.Group, absoluteIndexPath); err != nil { return err } website.User = req.User diff --git a/agent/app/service/website_utils.go b/agent/app/service/website_utils.go index dd3433f3d..e1e26d6f0 100644 --- a/agent/app/service/website_utils.go +++ b/agent/app/service/website_utils.go @@ -1032,8 +1032,7 @@ func checkIsLinkApp(website model.Website) bool { func chownRootDir(path string) error { cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(1 * time.Second)) - _, err := cmdMgr.RunWithStdoutBashCf(`chown -R 1000:1000 "%s"`, path) - if err != nil { + if err := cmdMgr.RunBashCf(`chown -R 1000:1000 "%s"`, path); err != nil { return err } return nil diff --git a/agent/constant/host_tool.go b/agent/constant/host_tool.go index 603117e9c..60f483b02 100644 --- a/agent/constant/host_tool.go +++ b/agent/constant/host_tool.go @@ -5,8 +5,4 @@ const ( Supervisor = "supervisor" SupervisorConfigPath = "SupervisorConfigPath" SupervisorServiceName = "SupervisorServiceName" - - ClamServiceNameCentOs = "clamd@scan.service" - ClamServiceNameUbuntu = "clamav-daemon.service" - FreshClamService = "clamav-freshclam.service" ) diff --git a/agent/init/lang/lang.go b/agent/init/lang/lang.go index 8bac6e928..8091e541f 100644 --- a/agent/init/lang/lang.go +++ b/agent/init/lang/lang.go @@ -62,9 +62,8 @@ func initLang() { downloadLangFromRemote(fileOp) return } - std, err := cmd.RunDefaultWithStdoutBashCf("cp -r %s %s", path.Join(tmpPath, "lang"), "/usr/local/bin/") - if err != nil { - global.LOG.Errorf("load lang from package failed, std: %s, err: %v", std, err) + if err := cmd.RunDefaultBashCf("cp -r %s %s", path.Join(tmpPath, "lang"), "/usr/local/bin/"); err != nil { + global.LOG.Errorf("load lang from package failed, %v", err) return } global.LOG.Info("init lang successful") @@ -74,9 +73,8 @@ func initLang() { downloadGeoFromRemote(fileOp, geoPath) return } - std, err := cmd.RunDefaultWithStdoutBashCf("mkdir %s && cp %s %s/", path.Dir(geoPath), path.Join(tmpPath, "GeoIP.mmdb"), path.Dir(geoPath)) - if err != nil { - global.LOG.Errorf("load geo ip from package failed, std: %s, err: %v", std, err) + if err := cmd.RunDefaultBashCf("mkdir %s && cp %s %s/", path.Dir(geoPath), path.Join(tmpPath, "GeoIP.mmdb"), path.Dir(geoPath)); err != nil { + global.LOG.Errorf("load geo ip from package failed, %v", err) return } global.LOG.Info("init geo ip successful") @@ -116,9 +114,8 @@ func downloadLangFromRemote(fileOp files.FileOp) { global.LOG.Error("download lang.tar.gz failed, no such file") return } - std, err := cmd.RunDefaultWithStdoutBashCf("tar zxvfC %s %s", "/usr/local/bin/lang.tar.gz", "/usr/local/bin/") - if err != nil { - fmt.Printf("decompress lang.tar.gz failed, std: %s, err: %v", std, err) + if err := cmd.RunDefaultBashCf("tar zxvfC %s %s", "/usr/local/bin/lang.tar.gz", "/usr/local/bin/"); err != nil { + global.LOG.Errorf("decompress lang.tar.gz failed, %v", err) return } _ = os.Remove("/usr/local/bin/lang.tar.gz") diff --git a/agent/utils/ai_tools/gpu/gpu.go b/agent/utils/ai_tools/gpu/gpu.go index d9969b311..7bed74464 100644 --- a/agent/utils/ai_tools/gpu/gpu.go +++ b/agent/utils/ai_tools/gpu/gpu.go @@ -26,7 +26,7 @@ func (n NvidiaSMI) LoadGpuInfo() (*common.GpuInfo, error) { cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(5 * time.Second)) itemData, err := cmdMgr.RunWithStdoutBashC("nvidia-smi -q -x") if err != nil { - return nil, fmt.Errorf("calling nvidia-smi failed, err: %w", err) + return nil, fmt.Errorf("calling nvidia-smi failed, %v", err) } data := []byte(itemData) version := "v11" diff --git a/agent/utils/ai_tools/xpu/xpu.go b/agent/utils/ai_tools/xpu/xpu.go index 5ae08d8dd..66702ab4d 100644 --- a/agent/utils/ai_tools/xpu/xpu.go +++ b/agent/utils/ai_tools/xpu/xpu.go @@ -8,7 +8,7 @@ import ( "sync" "time" - baseGlobal "github.com/1Panel-dev/1Panel/agent/global" + "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" ) @@ -45,31 +45,31 @@ func (x XpuSMI) loadDeviceData(device Device, wg *sync.WaitGroup, res *[]XPUSimp wgCmd.Wait() if xpuErr != nil { - baseGlobal.LOG.Errorf("calling xpu-smi discovery failed for device %d, err: %v\n", device.DeviceID, xpuErr) + global.LOG.Errorf("calling xpu-smi discovery failed for device %d, %v", device.DeviceID, xpuErr) return } var info Device if err := json.Unmarshal([]byte(xpuData), &info); err != nil { - baseGlobal.LOG.Errorf("xpuData json unmarshal failed for device %d, err: %v\n", device.DeviceID, err) + global.LOG.Errorf("xpuData json unmarshal failed for device %d, err: %v", device.DeviceID, err) return } bytes, err := strconv.ParseInt(info.MemoryPhysicalSizeByte, 10, 64) if err != nil { - baseGlobal.LOG.Errorf("Error parsing memory size for device %d, err: %v\n", device.DeviceID, err) + global.LOG.Errorf("Error parsing memory size for device %d, err: %v", device.DeviceID, err) return } xpu.Memory = fmt.Sprintf("%.1f MB", float64(bytes)/(1024*1024)) if statsErr != nil { - baseGlobal.LOG.Errorf("calling xpu-smi stats failed for device %d, err: %v\n", device.DeviceID, statsErr) + global.LOG.Errorf("calling xpu-smi stats failed for device %d, err: %v", device.DeviceID, statsErr) return } var stats DeviceStats if err := json.Unmarshal([]byte(statsData), &stats); err != nil { - baseGlobal.LOG.Errorf("statsData json unmarshal failed for device %d, err: %v\n", device.DeviceID, err) + global.LOG.Errorf("statsData json unmarshal failed for device %d, err: %v", device.DeviceID, err) return } @@ -95,7 +95,7 @@ func (x XpuSMI) LoadDashData() ([]XPUSimpleInfo, error) { cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(5 * time.Second)) data, err := cmdMgr.RunWithStdoutBashC("xpu-smi discovery -j") if err != nil { - return nil, fmt.Errorf("calling xpu-smi failed, err: %w", err) + return nil, fmt.Errorf("calling xpu-smi failed, %v", err) } var deviceInfo DeviceInfo @@ -124,7 +124,7 @@ func (x XpuSMI) LoadGpuInfo() (*XpuInfo, error) { cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(5 * time.Second)) data, err := cmdMgr.RunWithStdoutBashC("xpu-smi discovery -j") if err != nil { - return nil, fmt.Errorf("calling xpu-smi failed, err: %w", err) + return nil, fmt.Errorf("calling xpu-smi failed, %v", err) } var deviceInfo DeviceInfo if err := json.Unmarshal([]byte(data), &deviceInfo); err != nil { @@ -146,7 +146,7 @@ func (x XpuSMI) LoadGpuInfo() (*XpuInfo, error) { processData, err := cmdMgr.RunWithStdoutBashC("xpu-smi ps -j") if err != nil { - return nil, fmt.Errorf("calling xpu-smi ps failed, err: %w", err) + return nil, fmt.Errorf("calling xpu-smi ps failed, %s", err) } var psList DeviceUtilByProcList if err := json.Unmarshal([]byte(processData), &psList); err != nil { @@ -205,13 +205,13 @@ func (x XpuSMI) loadDeviceInfo(device Device, wg *sync.WaitGroup, res *XpuInfo, wgCmd.Wait() if xpuErr != nil { - baseGlobal.LOG.Errorf("calling xpu-smi discovery failed for device %d, err: %v\n", device.DeviceID, xpuErr) + global.LOG.Errorf("calling xpu-smi discovery failed for device %d, %v", device.DeviceID, xpuErr) return } var info Device if err := json.Unmarshal([]byte(xpuData), &info); err != nil { - baseGlobal.LOG.Errorf("xpuData json unmarshal failed for device %d, err: %v\n", device.DeviceID, err) + global.LOG.Errorf("xpuData json unmarshal failed for device %d, err: %v", device.DeviceID, err) return } @@ -220,20 +220,20 @@ func (x XpuSMI) loadDeviceInfo(device Device, wg *sync.WaitGroup, res *XpuInfo, bytes, err := strconv.ParseInt(info.MemoryPhysicalSizeByte, 10, 64) if err != nil { - baseGlobal.LOG.Errorf("Error parsing memory size for device %d, err: %v\n", device.DeviceID, err) + global.LOG.Errorf("Error parsing memory size for device %d, err: %v", device.DeviceID, err) return } xpu.Basic.Memory = fmt.Sprintf("%.1f MB", float64(bytes)/(1024*1024)) xpu.Basic.FreeMemory = info.MemoryFreeSizeByte if statsErr != nil { - baseGlobal.LOG.Errorf("calling xpu-smi stats failed for device %d, err: %v\n", device.DeviceID, statsErr) + global.LOG.Errorf("calling xpu-smi stats failed for device %d, err: %v", device.DeviceID, statsErr) return } var stats DeviceStats if err := json.Unmarshal([]byte(statsData), &stats); err != nil { - baseGlobal.LOG.Errorf("statsData json unmarshal failed for device %d, err: %v\n", device.DeviceID, err) + global.LOG.Errorf("statsData json unmarshal failed for device %d, err: %v", device.DeviceID, err) return } diff --git a/agent/utils/clam/clam.go b/agent/utils/clam/clam.go index d6e583f3a..686fcceea 100644 --- a/agent/utils/clam/clam.go +++ b/agent/utils/clam/clam.go @@ -14,7 +14,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/i18n" "github.com/1Panel-dev/1Panel/agent/utils/cmd" - "github.com/1Panel-dev/1Panel/agent/utils/systemctl" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/robfig/cron/v3" ) @@ -34,37 +34,13 @@ func AddScanTask(taskItem *task.Task, clam model.Clam, timeNow string) { } taskItem.Logf("clamdscan --fdpass %s %s", strategy, clam.Path) mgr := cmd.NewCommandMgr(cmd.WithIgnoreExist1(), cmd.WithTimeout(time.Duration(clam.Timeout)*time.Second), cmd.WithTask(*taskItem)) - stdout, err := mgr.RunWithStdoutBashCf("clamdscan --fdpass %s %s", strategy, clam.Path) - if err != nil { - return fmt.Errorf("clamdscan failed, stdout: %v, err: %v", stdout, err) + if err := mgr.RunBashCf("clamdscan --fdpass %s %s", strategy, clam.Path); err != nil { + return fmt.Errorf("clamdscan failed, %v", err) } return nil }, nil) } -func CheckClamIsActive(withCheck bool, clamRepo repo.IClamRepo) bool { - if withCheck { - isActive := false - exist1, _ := systemctl.IsExist(constant.ClamServiceNameCentOs) - if exist1 { - isActive, _ = systemctl.IsActive(constant.ClamServiceNameCentOs) - } - exist2, _ := systemctl.IsExist(constant.ClamServiceNameUbuntu) - if exist2 { - isActive, _ = systemctl.IsActive(constant.ClamServiceNameUbuntu) - } - if isActive { - return true - } - } - clams, _ := clamRepo.List(repo.WithByStatus(constant.StatusEnable)) - for i := 0; i < len(clams); i++ { - global.Cron.Remove(cron.EntryID(clams[i].EntryID)) - _ = clamRepo.Update(clams[i].ID, map[string]interface{}{"status": constant.StatusDisable, "entry_id": 0}) - } - return false -} - func AnalysisFromLog(pathItem string, record *model.ClamRecord) { file, err := os.ReadFile(pathItem) if err != nil { @@ -86,3 +62,22 @@ func AnalysisFromLog(pathItem string, record *model.ClamRecord) { } } } + +func StopAllClamJob(withCheck bool, clamRepo repo.IClamRepo) bool { + if withCheck { + isActive := false + isexist, _ := controller.CheckExist("clam") + if isexist { + isActive, _ = controller.CheckActive("clam") + } + if isActive { + return false + } + } + clams, _ := clamRepo.List(repo.WithByStatus(constant.StatusEnable)) + for i := 0; i < len(clams); i++ { + global.Cron.Remove(cron.EntryID(clams[i].EntryID)) + _ = clamRepo.Update(clams[i].ID, map[string]interface{}{"status": constant.StatusDisable, "entry_id": 0}) + } + return true +} diff --git a/agent/utils/cmd/cmdx.go b/agent/utils/cmd/cmdx.go index 0c3779d48..4303c1874 100644 --- a/agent/utils/cmd/cmdx.go +++ b/agent/utils/cmd/cmdx.go @@ -70,16 +70,14 @@ func (c *CommandHelper) RunBashCWithArgs(arg ...string) error { } func (c *CommandHelper) RunBashC(command string) error { - std, err := c.run("bash", "-c", command) - if err != nil { - return fmt.Errorf("handle failed, std: %s, err: %v", std, err) + if _, err := c.run("bash", "-c", command); err != nil { + return err } return nil } func (c *CommandHelper) RunBashCf(command string, arg ...interface{}) error { - std, err := c.run("bash", "-c", fmt.Sprintf(command, arg...)) - if err != nil { - return fmt.Errorf("handle failed, std: %s, err: %v", std, err) + if _, err := c.run("bash", "-c", fmt.Sprintf(command, arg...)); err != nil { + return err } return nil } @@ -237,16 +235,16 @@ func handleErr(stdout, stderr bytes.Buffer, ignoreExist1 bool, err error) (strin } } } - errMsg := "" - if len(stderr.String()) != 0 { - errMsg = fmt.Sprintf("stderr: %s", stderr.String()) + outItem := stdout.String() + errItem := stderr.String() + if len(errItem) != 0 && len(outItem) != 0 { + return outItem, fmt.Errorf("stdout: %s; stderr: %s, err: %v", outItem, errItem, err) } - if len(stdout.String()) != 0 { - if len(errMsg) != 0 { - errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String()) - } else { - errMsg = fmt.Sprintf("stdout: %s", stdout.String()) - } + if len(errItem) != 0 { + return outItem, fmt.Errorf("stderr: %s, err: %v", errItem, err) } - return errMsg, err + if len(outItem) != 0 { + return outItem, fmt.Errorf("stdout: %s, err: %v", outItem, err) + } + return "", err } diff --git a/agent/utils/common/common.go b/agent/utils/common/common.go index 6b0d6d271..23063185d 100644 --- a/agent/utils/common/common.go +++ b/agent/utils/common/common.go @@ -18,7 +18,6 @@ import ( "github.com/gin-gonic/gin" "github.com/1Panel-dev/1Panel/agent/buserr" - "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "golang.org/x/net/idna" ) @@ -398,28 +397,6 @@ func HandleIPList(content string) ([]string, error) { return res, nil } -func RestartService(core, agent, reload bool) { - command := "" - if reload { - command = "systemctl daemon-reload && " - } - switch { - case core && agent: - command += "systemctl restart 1panel-core.service && systemctl restart 1panel-agent.service" - case core: - command += "systemctl restart 1panel-core.service" - case agent: - command += "systemctl restart 1panel-agent.service" - default: - return - } - cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(1 * time.Second)) - std, err := cmdMgr.RunWithStdoutBashC(command) - if err != nil { - global.LOG.Errorf("restart 1panel service failed, err: %v, std: %s", err, std) - } -} - func GetSystemVersion(versionString string) string { re := regexp.MustCompile(`v(\d+\.\d+\.\d+)`) match := re.FindStringSubmatch(versionString) diff --git a/agent/utils/controller/controller.go b/agent/utils/controller/controller.go new file mode 100644 index 000000000..c913d892e --- /dev/null +++ b/agent/utils/controller/controller.go @@ -0,0 +1,197 @@ +package controller + +import ( + "errors" + "fmt" + "os/exec" + "strings" + + "github.com/1Panel-dev/1Panel/agent/global" + "github.com/1Panel-dev/1Panel/agent/utils/controller/manager" +) + +type Controller interface { + Name() string + IsActive(serviceName string) (bool, error) + IsEnable(serviceName string) (bool, error) + IsExist(serviceName string) (bool, error) + Status(serviceName string) (string, error) + + Operate(operate, serviceName string) error + + Reload() error +} + +func New() (Controller, error) { + managerOptions := []string{"systemd", "openrc", "sysvinit"} + for _, item := range managerOptions { + if _, err := exec.LookPath(item); err != nil { + continue + } + switch item { + case "systemd": + return manager.NewSystemd(), nil + case "openrc": + return manager.NewOpenrc(), nil + case "sysvinit": + return manager.NewSysvinit(), nil + } + } + return nil, errors.New("not support such manager initializatio") +} + +func Handle(operate, serviceName string) error { + service, err := LoadServiceName(serviceName) + if err != nil { + return err + } + client, err := New() + if err != nil { + return err + } + return client.Operate(operate, service) +} +func HandleStart(serviceName string) error { + service, err := LoadServiceName(serviceName) + if err != nil { + return err + } + return Handle("start", service) +} +func HandleStop(serviceName string) error { + service, err := LoadServiceName(serviceName) + if err != nil { + return err + } + return Handle("stop", service) +} +func HandleRestart(serviceName string) error { + service, err := LoadServiceName(serviceName) + if err != nil { + return err + } + return Handle("restart", service) +} + +func CheckExist(serviceName string) (bool, error) { + service, err := LoadServiceName(serviceName) + if err != nil { + return false, err + } + client, err := New() + if err != nil { + return false, err + } + b, er := client.IsExist(service) + return b, er +} +func CheckActive(serviceName string) (bool, error) { + service, err := LoadServiceName(serviceName) + if err != nil { + return false, err + } + client, err := New() + if err != nil { + return false, err + } + return client.IsActive(service) +} +func CheckEnable(serviceName string) (bool, error) { + service, err := LoadServiceName(serviceName) + if err != nil { + return false, err + } + client, err := New() + if err != nil { + return false, err + } + return client.IsEnable(service) +} + +func Reload() error { + client, err := New() + if err != nil { + return err + } + return client.Reload() +} + +func RestartPanel(core, agent, reload bool) { + client, err := New() + if err != nil { + global.LOG.Errorf("load client for controller failed, err: %v", err) + return + } + if reload { + if err := client.Reload(); err != nil { + global.LOG.Errorf("restart 1panel service failed, err: %v", err) + return + } + } + if agent { + if err := client.Operate("restart", "1panel-agent"); err != nil { + global.LOG.Errorf("restart 1panel agent service failed, err: %v", err) + return + } + } + if core { + if err := client.Operate("restart", "1panel-core"); err != nil { + global.LOG.Errorf("restart 1panel core service failed, err: %v", err) + return + } + } +} + +func LoadServiceName(keyword string) (string, error) { + client, err := New() + if err != nil { + return "", err + } + + processedName := loadProcessedName(client.Name(), keyword) + exist, err := client.IsExist(processedName) + if exist { + return processedName, nil + } + alistName := loadFromPredefined(client, keyword) + if len(alistName) != 0 { + return alistName, nil + } + return "", fmt.Errorf("find such service for %s failed", keyword) +} + +func loadProcessedName(mgr, keyword string) string { + keyword = strings.ToLower(keyword) + if strings.HasSuffix(keyword, ".service.socket") { + keyword = strings.TrimSuffix(keyword, ".service.socket") + ".socket" + } + if mgr != "systemd" { + keyword = strings.TrimSuffix(keyword, ".service") + return keyword + } + if !strings.HasSuffix(keyword, ".service") && !strings.HasSuffix(keyword, ".socket") { + keyword += ".service" + } + return keyword +} + +func loadFromPredefined(mgr Controller, keyword string) string { + predefinedMap := map[string][]string{ + "clam": {"clamav-daemon.service", "clamd@scan.service", "clamd"}, + "freshclam": {"clamav-freshclam.service", "freshclam.service"}, + "fail2ban": {"fail2ban.service", "fail2ban"}, + "supervisor": {"supervisord.service", "supervisor.service", "supervisord", "supervisor"}, + "ssh": {"sshd.service", "ssh.service", "sshd", "ssh"}, + "1panel-core": {"1panel-core.service", "1panel-cored"}, + "1panel-agent": {"1panel-agent.service", "1panel-agentd"}, + "docker": {"docker.service", "dockerd"}, + } + if val, ok := predefinedMap[keyword]; ok { + for _, item := range val { + if exist, _ := mgr.IsExist(item); exist { + return item + } + } + } + return "" +} diff --git a/agent/utils/controller/manager/common.go b/agent/utils/controller/manager/common.go new file mode 100644 index 000000000..2e84866a2 --- /dev/null +++ b/agent/utils/controller/manager/common.go @@ -0,0 +1,25 @@ +package manager + +import ( + "errors" + "strings" + "time" + + "github.com/1Panel-dev/1Panel/agent/global" + "github.com/1Panel-dev/1Panel/agent/utils/cmd" +) + +func handlerErr(out string, err error) error { + if err != nil { + if out != "" { + return errors.New(out) + } + return err + } + return nil +} + +func run(name string, args ...string) (string, error) { + global.LOG.Debugf("handle with controller `%s %s`", name, strings.Join(args, " ")) + return cmd.NewCommandMgr(cmd.WithTimeout(10*time.Second)).RunWithStdoutBashCf("LANGUAGE=en_US:en %s %s", name, strings.Join(args, " ")) +} diff --git a/agent/utils/controller/manager/openrc.go b/agent/utils/controller/manager/openrc.go new file mode 100644 index 000000000..68cb5ba57 --- /dev/null +++ b/agent/utils/controller/manager/openrc.go @@ -0,0 +1,61 @@ +package manager + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/1Panel-dev/1Panel/agent/utils/cmd" +) + +type Openrc struct{ toolCmd string } + +func NewOpenrc() *Openrc { + return &Openrc{toolCmd: "rc-service"} +} + +func (s *Openrc) Name() string { + return "openrc" +} +func (s *Openrc) IsActive(serviceName string) (bool, error) { + out, err := cmd.RunDefaultWithStdoutBashCf("if service %s status >/dev/null 2>&1; then echo 'active'; else echo 'inactive'; fi", serviceName) + if err != nil { + return false, err + } + return out == "active\n", nil +} +func (s *Openrc) IsEnable(serviceName string) (bool, error) { + out, err := cmd.RunDefaultWithStdoutBashCf("if ls /etc/rc*.d/S*%s >/dev/null 2>&1; then echo 'enabled'; else echo 'disabled'; fi", serviceName) + if err != nil { + return false, err + } + return out == "enabled\n", nil +} +func (s *Openrc) IsExist(serviceName string) (bool, error) { + _, err := os.Stat(filepath.Join("/etc/init.d", serviceName)) + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, fmt.Errorf("stat /etc/init.d/%s failed: %w", serviceName, err) + } + return true, nil +} +func (s *Openrc) Status(serviceName string) (string, error) { + return run(s.toolCmd, serviceName, "status") +} + +func (s *Openrc) Operate(operate, serviceName string) error { + switch operate { + case "enable": + return handlerErr(run("rc-update", "add", serviceName, "default")) + case "disable": + return handlerErr(run("rc-update", "del", serviceName, "default")) + default: + return handlerErr(run(s.toolCmd, serviceName, operate)) + } +} + +func (s *Openrc) Reload() error { + return nil +} diff --git a/agent/utils/controller/manager/snap.go b/agent/utils/controller/manager/snap.go new file mode 100644 index 000000000..a4410ee9f --- /dev/null +++ b/agent/utils/controller/manager/snap.go @@ -0,0 +1,54 @@ +package manager + +import ( + "strings" +) + +type Snap struct{ toolCmd string } + +func NewSnap() *Snap { + return &Snap{toolCmd: "snap"} +} + +func (s *Snap) IsExist(serviceName string) bool { + out, err := run(s.toolCmd, "services") + if err != nil { + return false + } + return strings.Contains(out, serviceName) +} + +func (s *Snap) IsActive(serviceName string) bool { + out, err := run(s.toolCmd, "services") + if err != nil { + return false + } + lines := strings.Split(out, "\n") + for _, line := range lines { + if strings.Contains(line, serviceName) && strings.Contains(line, "active") { + return true + } + } + return false +} + +func (s *Snap) IsEnable(serviceName string) bool { + out, err := run(s.toolCmd, "services") + if err != nil { + return false + } + lines := strings.Split(out, "\n") + for _, line := range lines { + if strings.Contains(line, serviceName) && strings.Contains(line, "enabled") { + return true + } + } + return false +} + +func (s *Snap) Operate(operate, serviceName string) error { + if s.IsExist(serviceName) { + return handlerErr(run(s.toolCmd, operate, serviceName)) + } + return nil +} diff --git a/agent/utils/controller/manager/systemd.go b/agent/utils/controller/manager/systemd.go new file mode 100644 index 000000000..8d6a2ecf7 --- /dev/null +++ b/agent/utils/controller/manager/systemd.go @@ -0,0 +1,75 @@ +package manager + +import ( + "strings" +) + +type Systemd struct{ toolCmd string } + +func NewSystemd() *Systemd { + return &Systemd{toolCmd: "systemctl"} +} + +func (s *Systemd) Name() string { + return "systemd" +} +func (s *Systemd) IsActive(serviceName string) (bool, error) { + out, err := run(s.toolCmd, "is-active", serviceName) + if err != nil && out != "inactive\n" { + if NewSnap().IsActive(serviceName) { + return true, nil + } + return false, err + } + return out == "active\n", nil +} + +func (s *Systemd) IsEnable(serviceName string) (bool, error) { + out, err := run(s.toolCmd, "is-enabled", serviceName) + if err != nil && out != "disabled\n" { + if serviceName == "sshd" && out == "alias\n" { + return s.IsEnable("ssh") + } + if NewSnap().IsEnable(serviceName) { + return true, nil + } + return false, err + } + return out == "enabled\n", nil +} + +func (s *Systemd) IsExist(serviceName string) (bool, error) { + out, err := run(s.toolCmd, "is-enabled", serviceName) + if err != nil && out != "enabled\n" { + if strings.Contains(out, "disabled") { + return true, err + } + if NewSnap().IsExist(serviceName) { + return true, nil + } + return false, err + } + return true, err +} + +func (s *Systemd) Status(serviceName string) (string, error) { + return run(s.toolCmd, "status", serviceName) +} +func (s *Systemd) Operate(operate, serviceName string) error { + out, err := run(s.toolCmd, operate, serviceName) + if err != nil { + if serviceName == "sshd" && strings.Contains(out, "alias name or linked unit file") { + return s.Operate(operate, "ssh") + } + if err := NewSnap().Operate(operate, serviceName); err == nil { + return nil + } + return handlerErr(run(s.toolCmd, operate, serviceName)) + } + return nil +} + +func (s *Systemd) Reload() error { + out, err := run(s.toolCmd, "daemon-reload") + return handlerErr(out, err) +} diff --git a/agent/utils/controller/manager/sysvinit.go b/agent/utils/controller/manager/sysvinit.go new file mode 100644 index 000000000..a1a8b1af5 --- /dev/null +++ b/agent/utils/controller/manager/sysvinit.go @@ -0,0 +1,54 @@ +package manager + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/1Panel-dev/1Panel/agent/utils/cmd" +) + +type Sysvinit struct{ toolCmd string } + +func NewSysvinit() *Sysvinit { + return &Sysvinit{toolCmd: "service"} +} + +func (s *Sysvinit) Name() string { + return "sysvinit" +} +func (s *Sysvinit) IsActive(serviceName string) (bool, error) { + out, err := cmd.RunDefaultWithStdoutBashCf("if service %s status >/dev/null 2>&1; then echo 'active'; else echo 'inactive'; fi", serviceName) + if err != nil { + return false, err + } + return out == "active\n", nil +} +func (s *Sysvinit) IsEnable(serviceName string) (bool, error) { + out, err := cmd.RunDefaultWithStdoutBashCf("if ls /etc/rc*.d/S*%s >/dev/null 2>&1; then echo 'enabled'; else echo 'disabled'; fi", serviceName) + if err != nil { + return false, err + } + return out == "enabled\n", nil +} +func (s *Sysvinit) IsExist(serviceName string) (bool, error) { + _, err := os.Stat(filepath.Join("/etc/init.d", serviceName)) + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, fmt.Errorf("stat /etc/init.d/%s failed: %w", serviceName, err) + } + return true, nil +} +func (s *Sysvinit) Status(serviceName string) (string, error) { + return run(s.toolCmd, serviceName, "status") +} + +func (s *Sysvinit) Operate(operate, serviceName string) error { + return handlerErr(run(s.toolCmd, serviceName, operate)) +} + +func (s *Sysvinit) Reload() error { + return nil +} diff --git a/agent/utils/files/file_op.go b/agent/utils/files/file_op.go index 5c035299e..f60a6895e 100644 --- a/agent/utils/files/file_op.go +++ b/agent/utils/files/file_op.go @@ -30,7 +30,6 @@ import ( "github.com/1Panel-dev/1Panel/agent/global" "github.com/mholt/archiver/v4" - "github.com/pkg/errors" "github.com/spf13/afero" ) @@ -178,10 +177,7 @@ func (f FileOp) ChownR(dst string, uid string, gid string, sub bool) error { cmdStr = fmt.Sprintf(`chown -R %s:%s "%s"`, uid, gid, dst) } cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(10 * time.Second)) - if msg, err := cmdMgr.RunWithStdoutBashC(cmdStr); err != nil { - if msg != "" { - return errors.New(msg) - } + if err := cmdMgr.RunBashC(cmdStr); err != nil { return err } return nil @@ -193,10 +189,7 @@ func (f FileOp) ChmodR(dst string, mode int64, sub bool) error { cmdStr = fmt.Sprintf(`%s chmod -R %v "%s"`, cmd.SudoHandleCmd(), fmt.Sprintf("%04o", mode), dst) } cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(10 * time.Second)) - if msg, err := cmdMgr.RunWithStdoutBashC(cmdStr); err != nil { - if msg != "" { - return errors.New(msg) - } + if err := cmdMgr.RunBashC(cmdStr); err != nil { return err } return nil @@ -208,10 +201,7 @@ func (f FileOp) ChmodRWithMode(dst string, mode fs.FileMode, sub bool) error { cmdStr = fmt.Sprintf(`%s chmod -R %v "%s"`, cmd.SudoHandleCmd(), fmt.Sprintf("%o", mode.Perm()), dst) } cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(10 * time.Second)) - if msg, err := cmdMgr.RunWithStdoutBashC(cmdStr); err != nil { - if msg != "" { - return errors.New(msg) - } + if err := cmdMgr.RunBashC(cmdStr); err != nil { return err } return nil diff --git a/agent/utils/firewall/client/firewalld.go b/agent/utils/firewall/client/firewalld.go index 8fe816f5d..8d510ea40 100644 --- a/agent/utils/firewall/client/firewalld.go +++ b/agent/utils/firewall/client/firewalld.go @@ -9,6 +9,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/buserr" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" + "github.com/1Panel-dev/1Panel/agent/utils/controller" ) var ForwardListRegex = regexp.MustCompile(`^port=(\d{1,5}):proto=(.+?):toport=(\d{1,5}):toaddr=(.*)$`) @@ -31,39 +32,35 @@ func (f *Firewall) Status() (bool, error) { func (f *Firewall) Version() (string, error) { stdout, err := cmd.RunDefaultWithStdoutBashC("LANGUAGE=en_US:en firewall-cmd --version") if err != nil { - return "", fmt.Errorf("load the firewall version failed, err: %s", stdout) + return "", fmt.Errorf("load the firewall version failed, %v", err) } return strings.ReplaceAll(stdout, "\n ", ""), nil } func (f *Firewall) Start() error { - stdout, err := cmd.RunDefaultWithStdoutBashC("systemctl start firewalld") - if err != nil { - return fmt.Errorf("enable the firewall failed, err: %s", stdout) + if err := controller.HandleStart("firewalld"); err != nil { + return fmt.Errorf("enable the firewall failed, err: %v", err) } return nil } func (f *Firewall) Stop() error { - stdout, err := cmd.RunDefaultWithStdoutBashC("systemctl stop firewalld") - if err != nil { - return fmt.Errorf("stop the firewall failed, err: %s", stdout) + if err := controller.HandleStop("firewalld"); err != nil { + return fmt.Errorf("stop the firewall failed, err: %v", err) } return nil } func (f *Firewall) Restart() error { - stdout, err := cmd.RunDefaultWithStdoutBashC("systemctl restart firewalld") - if err != nil { - return fmt.Errorf("restart the firewall failed, err: %s", stdout) + if err := controller.HandleRestart("firewalld"); err != nil { + return fmt.Errorf("restart the firewall failed, err: %v", err) } return nil } func (f *Firewall) Reload() error { - stdout, err := cmd.RunDefaultWithStdoutBashC("firewall-cmd --reload") - if err != nil { - return fmt.Errorf("reload firewall failed, err: %s", stdout) + if err := cmd.RunDefaultBashC("firewall-cmd --reload"); err != nil { + return fmt.Errorf("reload firewall failed, err: %v", err) } return nil } @@ -170,9 +167,8 @@ func (f *Firewall) Port(port FireInfo, operation string) error { return buserr.New("ErrCmdIllegal") } - stdout, err := cmd.RunDefaultWithStdoutBashCf("firewall-cmd --zone=public --%s-port=%s/%s --permanent", operation, port.Port, port.Protocol) - if err != nil { - return fmt.Errorf("%s (port: %s/%s strategy: %s) failed, err: %s", operation, port.Port, port.Protocol, port.Strategy, stdout) + if err := cmd.RunDefaultBashCf("firewall-cmd --zone=public --%s-port=%s/%s --permanent", operation, port.Port, port.Protocol); err != nil { + return fmt.Errorf("%s (port: %s/%s strategy: %s) failed, %v", operation, port.Port, port.Protocol, port.Strategy, err) } return nil } @@ -195,14 +191,12 @@ func (f *Firewall) RichRules(rule FireInfo, operation string) error { ruleStr += fmt.Sprintf("protocol=%s ", rule.Protocol) } ruleStr += rule.Strategy - stdout, err := cmd.RunDefaultWithStdoutBashCf("firewall-cmd --zone=public --%s-rich-rule '%s' --permanent", operation, ruleStr) - if err != nil { - return fmt.Errorf("%s rich rules (%s) failed, err: %s", operation, ruleStr, stdout) + if err := cmd.RunDefaultBashCf("firewall-cmd --zone=public --%s-rich-rule '%s' --permanent", operation, ruleStr); err != nil { + return fmt.Errorf("%s rich rules (%s) failed, %v", operation, ruleStr, err) } if len(rule.Address) == 0 { - stdout1, err := cmd.RunDefaultWithStdoutBashCf("firewall-cmd --zone=public --%s-rich-rule '%s' --permanent", operation, strings.ReplaceAll(ruleStr, "family=ipv4 ", "family=ipv6 ")) - if err != nil { - return fmt.Errorf("%s rich rules (%s) failed, err: %s", operation, strings.ReplaceAll(ruleStr, "family=ipv4 ", "family=ipv6 "), stdout1) + if err := cmd.RunDefaultBashCf("firewall-cmd --zone=public --%s-rich-rule '%s' --permanent", operation, strings.ReplaceAll(ruleStr, "family=ipv4 ", "family=ipv6 ")); err != nil { + return fmt.Errorf("%s rich rules (%s) failed, %v", operation, strings.ReplaceAll(ruleStr, "family=ipv4 ", "family=ipv6 "), err) } } return nil @@ -214,11 +208,10 @@ func (f *Firewall) PortForward(info Forward, operation string) error { ruleStr = fmt.Sprintf("firewall-cmd --zone=public --%s-forward-port=port=%s:proto=%s:toaddr=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.TargetIP, info.TargetPort) } - stdout, err := cmd.RunDefaultWithStdoutBashC(ruleStr) - if err != nil { - return fmt.Errorf("%s port forward failed, err: %s", operation, stdout) + if err := cmd.RunDefaultBashC(ruleStr); err != nil { + return fmt.Errorf("%s port forward failed, %s", operation, err) } - if err = f.Reload(); err != nil { + if err := f.Reload(); err != nil { return err } return nil @@ -250,13 +243,12 @@ func (f *Firewall) EnableForward() error { stdout, err := cmd.RunDefaultWithStdoutBashC("firewall-cmd --zone=public --query-masquerade") if err != nil { if strings.HasSuffix(strings.TrimSpace(stdout), "no") { - stdout, err = cmd.RunDefaultWithStdoutBashC("firewall-cmd --zone=public --add-masquerade --permanent") - if err != nil { - return fmt.Errorf("%s: %s", err, stdout) + if err := cmd.RunDefaultBashC("firewall-cmd --zone=public --add-masquerade --permanent"); err != nil { + return err } return f.Reload() } - return fmt.Errorf("%s: %s", err, stdout) + return err } return nil diff --git a/agent/utils/firewall/client/iptables.go b/agent/utils/firewall/client/iptables.go index f8a0bb603..dc3610a0b 100644 --- a/agent/utils/firewall/client/iptables.go +++ b/agent/utils/firewall/client/iptables.go @@ -39,37 +39,32 @@ func NewIptables() (*Iptables, error) { return iptables, nil } -func (iptables *Iptables) outf(tab, rule string, a ...any) (stdout string, err error) { +func (iptables *Iptables) out(tab, rule string) (string, error) { cmdMgr := cmd.NewCommandMgr(cmd.WithIgnoreExist1(), cmd.WithTimeout(20*time.Second)) - stdout, err = cmdMgr.RunWithStdoutBashCf("%s iptables -t %s %s", iptables.CmdStr, tab, fmt.Sprintf(rule, a...)) - if err != nil && stdout != "" { - global.LOG.Errorf("iptables failed, err: %s", stdout) + stdout, err := cmdMgr.RunWithStdoutBashCf("%s iptables -t %s %s", iptables.CmdStr, tab, rule) + if err != nil { + global.LOG.Errorf("iptables failed, %v", err) } - return + return stdout, nil } -func (iptables *Iptables) runf(tab, rule string, a ...any) error { - stdout, err := iptables.outf(tab, rule, a...) - if err != nil { - return fmt.Errorf("%s, %s", err, stdout) +func (iptables *Iptables) run(tab, rule string) error { + if _, err := iptables.out(tab, rule); err != nil { + return err } - if stdout != "" { - return fmt.Errorf("iptables error: %s", stdout) - } - return nil } func (iptables *Iptables) Check() error { stdout, err := cmd.RunDefaultWithStdoutBashC("cat /proc/sys/net/ipv4/ip_forward") if err != nil { - return fmt.Errorf("check ip_forward error: %w, output: %s", err, stdout) + return fmt.Errorf("check ip_forward failed, %v", err) } if strings.TrimSpace(stdout) == "0" { return fmt.Errorf("ipv4 forward disabled") } - chain, err := iptables.outf(NatTab, "-L -n | grep 'Chain %s'", PreRoutingChain) + chain, err := iptables.out(NatTab, fmt.Sprintf("-L -n | grep 'Chain %s'", PreRoutingChain)) if err != nil { return fmt.Errorf("failed to check chain: %w", err) } @@ -81,18 +76,18 @@ func (iptables *Iptables) Check() error { } func (iptables *Iptables) NewChain(tab, chain string) error { - return iptables.runf(tab, "-N %s", chain) + return iptables.run(tab, "-N "+chain) } func (iptables *Iptables) AppendChain(tab string, chain, chain1 string) error { - return iptables.runf(tab, "-A %s -j %s", chain, chain1) + return iptables.run(tab, fmt.Sprintf("-A %s -j %s", chain, chain1)) } func (iptables *Iptables) NatList(chain ...string) ([]IptablesNatInfo, error) { if len(chain) == 0 { chain = append(chain, PreRoutingChain) } - stdout, err := iptables.outf(NatTab, "-nvL %s --line-numbers", chain[0]) + stdout, err := iptables.out(NatTab, fmt.Sprintf("-nvL %s --line-numbers", chain[0])) if err != nil { return nil, err } @@ -132,11 +127,11 @@ func (iptables *Iptables) NatAdd(protocol, srcPort, dest, destPort, iface string iptablesArg += fmt.Sprintf(" -i %s", iface) } iptablesArg += fmt.Sprintf(" -p %s --dport %s -j DNAT --to-destination %s:%s", protocol, srcPort, dest, destPort) - if err := iptables.runf(NatTab, iptablesArg); err != nil { + if err := iptables.run(NatTab, iptablesArg); err != nil { return err } - if err := iptables.runf(NatTab, fmt.Sprintf( + if err := iptables.run(NatTab, fmt.Sprintf( "-A %s -d %s -p %s --dport %s -j MASQUERADE", PostRoutingChain, dest, @@ -146,7 +141,7 @@ func (iptables *Iptables) NatAdd(protocol, srcPort, dest, destPort, iface string return err } - if err := iptables.runf(FilterTab, fmt.Sprintf( + if err := iptables.run(FilterTab, fmt.Sprintf( "-A %s -d %s -p %s --dport %s -j ACCEPT", ForwardChain, dest, @@ -156,7 +151,7 @@ func (iptables *Iptables) NatAdd(protocol, srcPort, dest, destPort, iface string return err } - if err := iptables.runf(FilterTab, fmt.Sprintf( + if err := iptables.run(FilterTab, fmt.Sprintf( "-A %s -s %s -p %s --sport %s -j ACCEPT", ForwardChain, dest, @@ -171,7 +166,7 @@ func (iptables *Iptables) NatAdd(protocol, srcPort, dest, destPort, iface string iptablesArg += fmt.Sprintf(" -i %s", iface) } iptablesArg += fmt.Sprintf(" -p %s --dport %s -j REDIRECT --to-port %s", protocol, srcPort, destPort) - if err := iptables.runf(NatTab, iptablesArg); err != nil { + if err := iptables.run(NatTab, iptablesArg); err != nil { return err } } @@ -189,12 +184,12 @@ func (iptables *Iptables) NatAdd(protocol, srcPort, dest, destPort, iface string } func (iptables *Iptables) NatRemove(num string, protocol, srcPort, dest, destPort, iface string) error { - if err := iptables.runf(NatTab, "-D %s %s", PreRoutingChain, num); err != nil { + if err := iptables.run(NatTab, fmt.Sprintf("-D %s %s", PreRoutingChain, num)); err != nil { return err } if dest != "" && dest != "127.0.0.1" && dest != "localhost" { - if err := iptables.runf(NatTab, fmt.Sprintf( + if err := iptables.run(NatTab, fmt.Sprintf( "-D %s -d %s -p %s --dport %s -j MASQUERADE", PostRoutingChain, dest, @@ -204,7 +199,7 @@ func (iptables *Iptables) NatRemove(num string, protocol, srcPort, dest, destPor return err } - if err := iptables.runf(FilterTab, fmt.Sprintf( + if err := iptables.run(FilterTab, fmt.Sprintf( "-D %s -d %s -p %s --dport %s -j ACCEPT", ForwardChain, dest, @@ -214,7 +209,7 @@ func (iptables *Iptables) NatRemove(num string, protocol, srcPort, dest, destPor return err } - if err := iptables.runf(FilterTab, fmt.Sprintf( + if err := iptables.run(FilterTab, fmt.Sprintf( "-D %s -s %s -p %s --sport %s -j ACCEPT", ForwardChain, dest, @@ -238,13 +233,13 @@ func (iptables *Iptables) NatRemove(num string, protocol, srcPort, dest, destPor } func (iptables *Iptables) Reload() error { - if err := iptables.runf(NatTab, "-F %s", PreRoutingChain); err != nil { + if err := iptables.run(NatTab, "-F "+PreRoutingChain); err != nil { return err } - if err := iptables.runf(NatTab, "-F %s", PostRoutingChain); err != nil { + if err := iptables.run(NatTab, "-F "+PostRoutingChain); err != nil { return err } - if err := iptables.runf(FilterTab, "-F %s", ForwardChain); err != nil { + if err := iptables.run(FilterTab, "-F "+ForwardChain); err != nil { return err } diff --git a/agent/utils/firewall/client/ufw.go b/agent/utils/firewall/client/ufw.go index 883e58098..80be44c59 100644 --- a/agent/utils/firewall/client/ufw.go +++ b/agent/utils/firewall/client/ufw.go @@ -38,24 +38,22 @@ func (f *Ufw) Status() (bool, error) { func (f *Ufw) Version() (string, error) { stdout, err := cmd.RunDefaultWithStdoutBashCf("%s version | grep ufw", f.CmdStr) if err != nil { - return "", fmt.Errorf("load the firewall status failed, err: %s", stdout) + return "", fmt.Errorf("load the firewall status failed, %v", err) } info := strings.ReplaceAll(stdout, "\n", "") return strings.ReplaceAll(info, "ufw ", ""), nil } func (f *Ufw) Start() error { - stdout, err := cmd.RunDefaultWithStdoutBashCf("echo y | %s enable", f.CmdStr) - if err != nil { - return fmt.Errorf("enable the firewall failed, err: %s", stdout) + if err := cmd.RunDefaultBashCf("echo y | %s enable", f.CmdStr); err != nil { + return fmt.Errorf("enable the firewall failed, %v", err) } return nil } func (f *Ufw) Stop() error { - stdout, err := cmd.RunDefaultWithStdoutBashCf("%s disable", f.CmdStr) - if err != nil { - return fmt.Errorf("stop the firewall failed, err: %s", stdout) + if err := cmd.RunDefaultBashCf("%s disable", f.CmdStr); err != nil { + return fmt.Errorf("stop the firewall failed, %v", err) } return nil } @@ -184,9 +182,8 @@ func (f *Ufw) Port(port FireInfo, operation string) error { if len(port.Protocol) != 0 { command += fmt.Sprintf("/%s", port.Protocol) } - stdout, err := cmd.RunDefaultWithStdoutBashC(command) - if err != nil { - return fmt.Errorf("%s (%s) failed, err: %s", operation, command, stdout) + if err := cmd.RunDefaultBashC(command); err != nil { + return fmt.Errorf("%s (%s) failed, %v", operation, command, err) } return nil } @@ -224,13 +221,12 @@ func (f *Ufw) RichRules(rule FireInfo, operation string) error { stdout, err := cmd.RunDefaultWithStdoutBashC(ruleStr) if err != nil { if strings.Contains(stdout, "ERROR: Invalid position") || strings.Contains(stdout, "ERROR: 无效位置") { - stdout, err := cmd.RunDefaultWithStdoutBashC(strings.ReplaceAll(ruleStr, "insert 1 ", "")) - if err != nil { - return fmt.Errorf("%s rich rules (%s), failed, err: %s", operation, ruleStr, stdout) + if err := cmd.RunDefaultBashC(strings.ReplaceAll(ruleStr, "insert 1 ", "")); err != nil { + return fmt.Errorf("%s rich rules (%s), failed, %v", operation, ruleStr, err) } return nil } - return fmt.Errorf("%s rich rules (%s), failed, err: %s", operation, ruleStr, stdout) + return fmt.Errorf("%s rich rules (%s), failed, %v", operation, ruleStr, err) } return nil } diff --git a/agent/utils/ntp/ntp.go b/agent/utils/ntp/ntp.go index c7979bf18..c50e9c41a 100644 --- a/agent/utils/ntp/ntp.go +++ b/agent/utils/ntp/ntp.go @@ -62,9 +62,8 @@ func GetRemoteTime(site string) (time.Time, error) { func UpdateSystemTime(dateTime string) error { system := runtime.GOOS if system == "linux" { - stdout2, err := cmd.RunDefaultWithStdoutBashCf(`%s date -s "%s"`, cmd.SudoHandleCmd(), dateTime) - if err != nil { - return fmt.Errorf("update system time failed,stdout: %s, err: %v", stdout2, err) + if err := cmd.RunDefaultBashCf(`%s date -s "%s"`, cmd.SudoHandleCmd(), dateTime); err != nil { + return fmt.Errorf("update system time failed, %v", err) } return nil } @@ -74,9 +73,8 @@ func UpdateSystemTime(dateTime string) error { func UpdateSystemTimeZone(timezone string) error { system := runtime.GOOS if system == "linux" { - stdout, err := cmd.RunDefaultWithStdoutBashCf(`%s timedatectl set-timezone "%s"`, cmd.SudoHandleCmd(), timezone) - if err != nil { - return fmt.Errorf("update system time zone failed, stdout: %s, err: %v", stdout, err) + if err := cmd.RunDefaultBashCf(`%s timedatectl set-timezone "%s"`, cmd.SudoHandleCmd(), timezone); err != nil { + return fmt.Errorf("update system time zone failed, %v", err) } return nil } diff --git a/agent/utils/systemctl/systemctl.go b/agent/utils/systemctl/systemctl.go deleted file mode 100644 index 0a97844a3..000000000 --- a/agent/utils/systemctl/systemctl.go +++ /dev/null @@ -1,116 +0,0 @@ -package systemctl - -import ( - "bytes" - "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 isSnapService(serviceName string) bool { - cmd := exec.Command("snap", "services") - var out bytes.Buffer - cmd.Stdout = &out - if err := cmd.Run(); err != nil { - return false - } - return strings.Contains(out.String(), serviceName) -} - -func isSnapServiceActive(serviceName string) bool { - cmd := exec.Command("snap", "services") - var out bytes.Buffer - cmd.Stdout = &out - if err := cmd.Run(); err != nil { - return false - } - lines := strings.Split(out.String(), "\n") - for _, line := range lines { - if strings.Contains(line, serviceName) && strings.Contains(line, "active") { - return true - } - } - return false -} - -func IsActive(serviceName string) (bool, error) { - out, err := RunSystemCtl("is-active", serviceName) - if err == nil { - return strings.TrimSpace(out) == "active", nil - } - - if isSnapServiceActive(serviceName) { - return true, nil - } - return false, fmt.Errorf("service %s is not active: %v", serviceName, err) -} - -func IsEnable(serviceName string) (bool, error) { - out, err := RunSystemCtl("is-enabled", serviceName) - if err == nil { - return strings.TrimSpace(out) == "enabled", nil - } - - if isSnapServiceActive(serviceName) { - return true, nil - } - return false, fmt.Errorf("failed to determine if service %s is enabled: %v", serviceName, err) -} - -func IsExist(serviceName string) (bool, error) { - out, err := RunSystemCtl("is-enabled", serviceName) - if err == nil || strings.Contains(out, "disabled") { - return true, nil - } - if isSnapService(serviceName) { - return true, nil - } - return false, 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) - if err == nil { - return nil - } - if isSnapService(serviceName) { - cmd := exec.Command("snap", "restart", serviceName) - output, snapErr := cmd.CombinedOutput() - return handlerErr(string(output), snapErr) - } - return handlerErr(out, err) -} - -func Operate(operate, serviceName string) error { - out, err := RunSystemCtl(operate, serviceName) - if err == nil { - return nil - } - - if isSnapService(serviceName) && (operate == "start" || operate == "stop" || operate == "restart") { - cmd := exec.Command("snap", operate, serviceName) - output, snapErr := cmd.CombinedOutput() - return handlerErr(string(output), snapErr) - } - return handlerErr(out, err) -} diff --git a/agent/utils/toolbox/fail2ban.go b/agent/utils/toolbox/fail2ban.go index 2adcc814a..8ac9f5e3a 100644 --- a/agent/utils/toolbox/fail2ban.go +++ b/agent/utils/toolbox/fail2ban.go @@ -8,7 +8,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" - "github.com/1Panel-dev/1Panel/agent/utils/systemctl" + "github.com/1Panel-dev/1Panel/agent/utils/controller" ) type Fail2ban struct{} @@ -23,15 +23,14 @@ type FirewallClient interface { } func NewFail2Ban() (*Fail2ban, error) { - isExist, _ := systemctl.IsExist("fail2ban.service") + isExist, _ := controller.CheckExist("fail2ban.service") if isExist { if _, err := os.Stat(defaultPath); err != nil { if err := initLocalFile(); err != nil { return nil, err } - stdout, err := cmd.RunDefaultWithStdoutBashC("systemctl restart fail2ban.service") - if err != nil { - global.LOG.Errorf("restart fail2ban failed, err: %s", stdout) + if err := controller.HandleRestart("fail2ban.service"); err != nil { + global.LOG.Errorf("restart fail2ban failed, err: %v", err) return nil, err } } @@ -40,9 +39,9 @@ func NewFail2Ban() (*Fail2ban, error) { } func (f *Fail2ban) Status() (bool, bool, bool) { - isEnable, _ := systemctl.IsEnable("fail2ban.service") - isActive, _ := systemctl.IsActive("fail2ban.service") - isExist, _ := systemctl.IsExist("fail2ban.service") + isEnable, _ := controller.CheckEnable("fail2ban.service") + isActive, _ := controller.CheckActive("fail2ban.service") + isExist, _ := controller.CheckExist("fail2ban.service") return isEnable, isActive, isExist } @@ -50,7 +49,7 @@ func (f *Fail2ban) Status() (bool, bool, bool) { func (f *Fail2ban) Version() string { stdout, err := cmd.RunDefaultWithStdoutBashC("fail2ban-client version") if err != nil { - global.LOG.Errorf("load the fail2ban version failed, err: %s", stdout) + global.LOG.Errorf("load the fail2ban version failed, %v", err) return "-" } return strings.ReplaceAll(stdout, "\n", "") @@ -59,15 +58,13 @@ func (f *Fail2ban) Version() string { func (f *Fail2ban) Operate(operate string) error { switch operate { case "start", "restart", "stop", "enable", "disable": - stdout, err := cmd.RunDefaultWithStdoutBashCf("systemctl %s fail2ban.service", operate) - if err != nil { - return fmt.Errorf("%s the fail2ban.service failed, err: %s", operate, stdout) + if err := controller.Handle(operate, "fail2ban.service"); err != nil { + return fmt.Errorf("%s the fail2ban.service failed, err: %v", operate, err) } return nil case "reload": - stdout, err := cmd.RunDefaultWithStdoutBashC("fail2ban-client reload") - if err != nil { - return fmt.Errorf("fail2ban-client reload, err: %s", stdout) + if err := cmd.RunDefaultBashC("fail2ban-client reload"); err != nil { + return fmt.Errorf("fail2ban-client reload, %v", err) } return nil default: @@ -159,9 +156,9 @@ action = %(action_mwl)s logpath = $logpath` banaction := "" - if active, _ := systemctl.IsActive("firewalld"); active { + if active, _ := controller.CheckActive("firewalld"); active { banaction = "firewallcmd-ipset" - } else if active, _ := systemctl.IsActive("ufw"); active { + } else if active, _ := controller.CheckActive("ufw"); active { banaction = "ufw" } else { banaction = "iptables-allports" diff --git a/agent/utils/toolbox/pure-ftpd.go b/agent/utils/toolbox/pure-ftpd.go index ee9618a3e..63ac63b98 100644 --- a/agent/utils/toolbox/pure-ftpd.go +++ b/agent/utils/toolbox/pure-ftpd.go @@ -2,7 +2,6 @@ package toolbox import ( "bufio" - "errors" "fmt" "os" "os/user" @@ -13,7 +12,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" - "github.com/1Panel-dev/1Panel/agent/utils/systemctl" + "github.com/1Panel-dev/1Panel/agent/utils/controller" "github.com/1Panel-dev/1Panel/agent/utils/toolbox/helper" ) @@ -63,29 +62,26 @@ func NewFtpClient() (*Ftp, error) { groupItem, err := user.LookupGroupId("1000") if err == nil { - stdout2, err := cmd.RunDefaultWithStdoutBashCf("useradd -u 1000 -g %s %s", groupItem.Name, "1panel") - if err != nil { - return nil, errors.New(stdout2) + if err := cmd.RunDefaultBashCf("useradd -u 1000 -g %s %s", groupItem.Name, "1panel"); err != nil { + return nil, err } return &Ftp{DefaultUser: "1panel", DefaultGroup: groupItem.Name}, nil } if err.Error() != user.UnknownGroupIdError("1000").Error() { return nil, err } - stdout, err := cmd.RunDefaultWithStdoutBashC("groupadd -g 1000 1panel") - if err != nil { - return nil, errors.New(string(stdout)) + if err := cmd.RunDefaultBashC("groupadd -g 1000 1panel"); err != nil { + return nil, err } - stdout2, err := cmd.RunDefaultWithStdoutBashC("useradd -u 1000 -g 1panel 1panel") - if err != nil { - return nil, errors.New(stdout2) + if err := cmd.RunDefaultBashC("useradd -u 1000 -g 1panel 1panel"); err != nil { + return nil, err } return &Ftp{DefaultUser: "1panel", DefaultGroup: "1panel"}, nil } func (f *Ftp) Status() (bool, bool) { - isActive, _ := systemctl.IsActive("pure-ftpd.service") - isExist, _ := systemctl.IsExist("pure-ftpd.service") + isActive, _ := controller.CheckActive("pure-ftpd.service") + isExist, _ := controller.CheckExist("pure-ftpd.service") return isActive, isExist } @@ -93,9 +89,8 @@ func (f *Ftp) Status() (bool, bool) { func (f *Ftp) Operate(operate string) error { switch operate { case "start", "restart", "stop": - stdout, err := cmd.RunDefaultWithStdoutBashCf("systemctl %s pure-ftpd.service", operate) - if err != nil { - return fmt.Errorf("%s the pure-ftpd.service failed, err: %s", operate, stdout) + if err := controller.Handle(operate, "pure-ftpd.service"); err != nil { + return fmt.Errorf("%s the pure-ftpd.service failed, err: %v", operate, err) } return nil default: @@ -119,17 +114,15 @@ func (f *Ftp) UserAdd(username, passwd, path string) error { return err } _ = f.Reload() - std2, err := cmd.RunDefaultWithStdoutBashCf("chown -R %s:%s %s", f.DefaultUser, f.DefaultGroup, path) - if err != nil { - return errors.New(std2) + if err := cmd.RunDefaultBashCf("chown -R %s:%s %s", f.DefaultUser, f.DefaultGroup, path); err != nil { + return err } return nil } func (f *Ftp) UserDel(username string) error { - std, err := cmd.RunDefaultWithStdoutBashCf("pure-pw userdel %s", username) - if err != nil { - return errors.New(std) + if err := cmd.RunDefaultBashCf("pure-pw userdel %s", username); err != nil { + return err } _ = f.Reload() return nil @@ -186,13 +179,11 @@ func (f *Ftp) SetPasswd(username, passwd string) error { } func (f *Ftp) SetPath(username, path string) error { - std, err := cmd.RunDefaultWithStdoutBashCf("pure-pw usermod %s -d %s", username, path) - if err != nil { - return errors.New(std) + if err := cmd.RunDefaultBashCf("pure-pw usermod %s -d %s", username, path); err != nil { + return err } - std2, err := cmd.RunDefaultWithStdoutBashCf("chown -R %s:%s %s", f.DefaultUser, f.DefaultGroup, path) - if err != nil { - return errors.New(std2) + if err := cmd.RunDefaultBashCf("chown -R %s:%s %s", f.DefaultUser, f.DefaultGroup, path); err != nil { + return err } return nil } @@ -202,9 +193,8 @@ func (f *Ftp) SetStatus(username, status string) error { if status == constant.StatusDisable { statusItem = "1" } - std, err := cmd.RunDefaultWithStdoutBashCf("pure-pw usermod %s -r %s", username, statusItem) - if err != nil { - return errors.New(std) + if err := cmd.RunDefaultBashCf("pure-pw usermod %s -r %s", username, statusItem); err != nil { + return err } return nil } @@ -212,7 +202,7 @@ func (f *Ftp) SetStatus(username, status string) error { func (f *Ftp) LoadList() ([]FtpList, error) { std, err := cmd.RunDefaultWithStdoutBashC("pure-pw list") if err != nil { - return nil, errors.New(std) + return nil, err } var lists []FtpList lines := strings.Split(std, "\n") @@ -223,7 +213,7 @@ func (f *Ftp) LoadList() ([]FtpList, error) { } std2, err := cmd.RunDefaultWithStdoutBashCf("pure-pw show %s | grep 'Allowed client IPs :'", parts[0]) if err != nil { - global.LOG.Errorf("handle pure-pw show %s failed, err: %v", parts[0], std2) + global.LOG.Errorf("handle pure-pw show %s failed, %v", parts[0], err) continue } status := constant.StatusDisable @@ -237,9 +227,8 @@ func (f *Ftp) LoadList() ([]FtpList, error) { } func (f *Ftp) Reload() error { - std, err := cmd.RunDefaultWithStdoutBashC("pure-pw mkdb") - if err != nil { - return errors.New(std) + if err := cmd.RunDefaultBashC("pure-pw mkdb"); err != nil { + return err } return nil } @@ -296,7 +285,7 @@ func (f *Ftp) LoadLogs(user, operation string) ([]FtpLog, error) { } func handleGunzip(path string) error { - if _, err := cmd.RunDefaultWithStdoutBashCf("gunzip %s", path); err != nil { + if err := cmd.RunDefaultBashCf("gunzip %s", path); err != nil { return err } return nil diff --git a/core/app/service/setting.go b/core/app/service/setting.go index 88bc548fb..29539ff60 100644 --- a/core/app/service/setting.go +++ b/core/app/service/setting.go @@ -26,8 +26,8 @@ import ( "github.com/1Panel-dev/1Panel/core/buserr" "github.com/1Panel-dev/1Panel/core/constant" "github.com/1Panel-dev/1Panel/core/global" - "github.com/1Panel-dev/1Panel/core/utils/cmd" "github.com/1Panel-dev/1Panel/core/utils/common" + "github.com/1Panel-dev/1Panel/core/utils/controller" "github.com/1Panel-dev/1Panel/core/utils/encrypt" "github.com/1Panel-dev/1Panel/core/utils/firewall" "github.com/1Panel-dev/1Panel/core/utils/req_helper/proxy_local" @@ -192,10 +192,7 @@ func (u *SettingService) UpdateBindInfo(req dto.BindInfo) error { } go func() { time.Sleep(1 * time.Second) - _, err := cmd.RunDefaultWithStdoutBashC("systemctl restart 1panel-core.service") - if err != nil { - global.LOG.Errorf("restart system with new bind info failed, err: %v", err) - } + controller.RestartPanel(true, false, false) }() return nil } @@ -261,9 +258,7 @@ func (u *SettingService) UpdatePort(port uint) error { } go func() { time.Sleep(1 * time.Second) - if _, err := cmd.RunDefaultWithStdoutBashC("systemctl restart 1panel-core.service"); err != nil { - global.LOG.Errorf("restart system port failed, err: %v", err) - } + controller.RestartPanel(true, false, false) }() return nil } @@ -282,10 +277,7 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error { _ = os.Remove(path.Join(secretDir, "server.key")) go func() { time.Sleep(1 * time.Second) - _, err := cmd.RunDefaultWithStdoutBashC("systemctl restart 1panel-core.service") - if err != nil { - global.LOG.Errorf("restart system failed, err: %v", err) - } + controller.RestartPanel(true, false, false) }() return nil } @@ -380,10 +372,7 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error { if req.SSL != status { go func() { time.Sleep(1 * time.Second) - _, err := cmd.RunDefaultWithStdoutBashC("systemctl restart 1panel-core.service") - if err != nil { - global.LOG.Errorf("restart system failed, err: %v", err) - } + controller.RestartPanel(true, false, false) }() } if err := settingRepo.Update("SSL", req.SSL); err != nil { diff --git a/core/app/service/upgrade.go b/core/app/service/upgrade.go index 27a326505..f822c44a1 100644 --- a/core/app/service/upgrade.go +++ b/core/app/service/upgrade.go @@ -10,7 +10,6 @@ import ( "sort" "strconv" "strings" - "time" "github.com/1Panel-dev/1Panel/core/app/dto" "github.com/1Panel-dev/1Panel/core/app/model" @@ -20,6 +19,7 @@ import ( "github.com/1Panel-dev/1Panel/core/global" "github.com/1Panel-dev/1Panel/core/utils/cmd" "github.com/1Panel-dev/1Panel/core/utils/common" + "github.com/1Panel-dev/1Panel/core/utils/controller" "github.com/1Panel-dev/1Panel/core/utils/files" "github.com/1Panel-dev/1Panel/core/utils/req_helper" ) @@ -207,10 +207,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error { global.CONF.Base.Version = req.Version _ = settingRepo.Update("SystemStatus", "Free") - cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(10 * time.Second)) - _, _ = cmdMgr.RunWithStdoutBashC("systemctl daemon-reload") - _, _ = cmdMgr.RunWithStdoutBashC("systemctl restart 1panel-agent.service") - _, _ = cmdMgr.RunWithStdoutBashC("systemctl restart 1panel-core.service") + controller.RestartPanel(true, true, true) }() return nil } diff --git a/core/cmd/server/cmd/restore.go b/core/cmd/server/cmd/restore.go index 64e7cc243..55342102c 100644 --- a/core/cmd/server/cmd/restore.go +++ b/core/cmd/server/cmd/restore.go @@ -11,6 +11,7 @@ import ( "github.com/1Panel-dev/1Panel/core/i18n" cmdUtils "github.com/1Panel-dev/1Panel/core/utils/cmd" "github.com/1Panel-dev/1Panel/core/utils/common" + "github.com/1Panel-dev/1Panel/core/utils/controller" "github.com/1Panel-dev/1Panel/core/utils/files" "github.com/spf13/cobra" @@ -88,11 +89,7 @@ var restoreCmd = &cobra.Command{ fmt.Println(i18n.GetMsgByKeyForCmd("RestoreStep5")) fmt.Println(i18n.GetMsgByKeyForCmd("RestoreSuccessful")) - _, _ = cmdUtils.RunDefaultWithStdoutBashC("systemctl daemon-reload") - std, err := cmdUtils.RunDefaultWithStdoutBashC("1pctl restart all") - if err != nil { - fmt.Println(std) - } + controller.RestartPanel(true, true, true) return nil }, } diff --git a/core/init/geo/lang.go b/core/init/geo/lang.go index cd1b0c12c..44c9bd620 100644 --- a/core/init/geo/lang.go +++ b/core/init/geo/lang.go @@ -61,9 +61,8 @@ func initLang() { downloadLangFromRemote() return } - std, err := cmd.RunDefaultWithStdoutBashCf("cp -r %s %s", path.Join(tmpPath, "lang"), "/usr/local/bin/") - if err != nil { - global.LOG.Errorf("load lang from package failed, std: %s, err: %v", std, err) + if err := cmd.RunDefaultBashCf("cp -r %s %s", path.Join(tmpPath, "lang"), "/usr/local/bin/"); err != nil { + global.LOG.Errorf("load lang from package failed, %v", err) return } global.LOG.Info("init lang successful") @@ -73,9 +72,8 @@ func initLang() { downloadGeoFromRemote(geoPath) return } - std, err := cmd.RunDefaultWithStdoutBashCf("mkdir %s && cp %s %s/", path.Dir(geoPath), path.Join(tmpPath, "GeoIP.mmdb"), path.Dir(geoPath)) - if err != nil { - global.LOG.Errorf("load geo ip from package failed, std: %s, err: %v", std, err) + if err := cmd.RunDefaultBashCf("mkdir %s && cp %s %s/", path.Dir(geoPath), path.Join(tmpPath, "GeoIP.mmdb"), path.Dir(geoPath)); err != nil { + global.LOG.Errorf("load geo ip from package failed, %v", err) return } global.LOG.Info("init geo ip successful") @@ -115,9 +113,8 @@ func downloadLangFromRemote() { global.LOG.Error("download lang.tar.gz failed, no such file") return } - std, err := cmd.RunDefaultWithStdoutBashCf("tar zxvfC %s %s", "/usr/local/bin/lang.tar.gz", "/usr/local/bin/") - if err != nil { - fmt.Printf("decompress lang.tar.gz failed, std: %s, err: %v", std, err) + if err := cmd.RunDefaultBashCf("tar zxvfC %s %s", "/usr/local/bin/lang.tar.gz", "/usr/local/bin/"); err != nil { + global.LOG.Errorf("decompress lang.tar.gz failed, %v", err) return } _ = os.Remove("/usr/local/bin/lang.tar.gz") diff --git a/core/utils/controller/controller.go b/core/utils/controller/controller.go new file mode 100644 index 000000000..137bacade --- /dev/null +++ b/core/utils/controller/controller.go @@ -0,0 +1,197 @@ +package controller + +import ( + "errors" + "fmt" + "os/exec" + "strings" + + "github.com/1Panel-dev/1Panel/core/global" + "github.com/1Panel-dev/1Panel/core/utils/controller/manager" +) + +type Controller interface { + Name() string + IsActive(serviceName string) (bool, error) + IsEnable(serviceName string) (bool, error) + IsExist(serviceName string) (bool, error) + Status(serviceName string) (string, error) + + Operate(operate, serviceName string) error + + Reload() error +} + +func New() (Controller, error) { + managerOptions := []string{"systemd", "openrc", "sysvinit"} + for _, item := range managerOptions { + if _, err := exec.LookPath(item); err != nil { + continue + } + switch item { + case "systemd": + return manager.NewSystemd(), nil + case "openrc": + return manager.NewOpenrc(), nil + case "sysvinit": + return manager.NewSysvinit(), nil + } + } + return nil, errors.New("not support such manager initializatio") +} + +func Handle(operate, serviceName string) error { + service, err := LoadServiceName(serviceName) + if err != nil { + return err + } + client, err := New() + if err != nil { + return err + } + return client.Operate(operate, service) +} +func HandleStart(serviceName string) error { + service, err := LoadServiceName(serviceName) + if err != nil { + return err + } + return Handle("start", service) +} +func HandleStop(serviceName string) error { + service, err := LoadServiceName(serviceName) + if err != nil { + return err + } + return Handle("stop", service) +} +func HandleRestart(serviceName string) error { + service, err := LoadServiceName(serviceName) + if err != nil { + return err + } + return Handle("restart", service) +} + +func CheckExist(serviceName string) (bool, error) { + service, err := LoadServiceName(serviceName) + if err != nil { + return false, err + } + client, err := New() + if err != nil { + return false, err + } + b, er := client.IsExist(service) + return b, er +} +func CheckActive(serviceName string) (bool, error) { + service, err := LoadServiceName(serviceName) + if err != nil { + return false, err + } + client, err := New() + if err != nil { + return false, err + } + return client.IsActive(service) +} +func CheckEnable(serviceName string) (bool, error) { + service, err := LoadServiceName(serviceName) + if err != nil { + return false, err + } + client, err := New() + if err != nil { + return false, err + } + return client.IsEnable(service) +} + +func Reload() error { + client, err := New() + if err != nil { + return err + } + return client.Reload() +} + +func RestartPanel(core, agent, reload bool) { + client, err := New() + if err != nil { + global.LOG.Errorf("load client for controller failed, err: %v", err) + return + } + if reload { + if err := client.Reload(); err != nil { + global.LOG.Errorf("restart 1panel service failed, err: %v", err) + return + } + } + if agent { + if err := client.Operate("restart", "1panel-agent"); err != nil { + global.LOG.Errorf("restart 1panel agent service failed, err: %v", err) + return + } + } + if core { + if err := client.Operate("restart", "1panel-core"); err != nil { + global.LOG.Errorf("restart 1panel core service failed, err: %v", err) + return + } + } +} + +func LoadServiceName(keyword string) (string, error) { + client, err := New() + if err != nil { + return "", err + } + + processedName := loadProcessedName(client.Name(), keyword) + exist, err := client.IsExist(processedName) + if exist { + return processedName, nil + } + alistName := loadFromPredefined(client, keyword) + if len(alistName) != 0 { + return alistName, nil + } + return "", fmt.Errorf("find such service for %s failed", keyword) +} + +func loadProcessedName(mgr, keyword string) string { + keyword = strings.ToLower(keyword) + if strings.HasSuffix(keyword, ".service.socket") { + keyword = strings.TrimSuffix(keyword, ".service.socket") + ".socket" + } + if mgr != "systemd" { + keyword = strings.TrimSuffix(keyword, ".service") + return keyword + } + if !strings.HasSuffix(keyword, ".service") && !strings.HasSuffix(keyword, ".socket") { + keyword += ".service" + } + return keyword +} + +func loadFromPredefined(mgr Controller, keyword string) string { + predefinedMap := map[string][]string{ + "clam": {"clamav-daemon.service", "clamd@scan.service", "clamd"}, + "freshclam": {"clamav-freshclam.service", "freshclam.service"}, + "fail2ban": {"fail2ban.service", "fail2ban"}, + "supervisor": {"supervisord.service", "supervisor.service", "supervisord", "supervisor"}, + "ssh": {"sshd.service", "ssh.service", "sshd", "ssh"}, + "1panel-core": {"1panel-core.service", "1panel-cored"}, + "1panel-agent": {"1panel-agent.service", "1panel-agentd"}, + "docker": {"docker.service", "dockerd"}, + } + if val, ok := predefinedMap[keyword]; ok { + for _, item := range val { + if exist, _ := mgr.IsExist(item); exist { + return item + } + } + } + return "" +} diff --git a/core/utils/controller/manager/common.go b/core/utils/controller/manager/common.go new file mode 100644 index 000000000..487a966a6 --- /dev/null +++ b/core/utils/controller/manager/common.go @@ -0,0 +1,25 @@ +package manager + +import ( + "errors" + "strings" + "time" + + "github.com/1Panel-dev/1Panel/core/global" + "github.com/1Panel-dev/1Panel/core/utils/cmd" +) + +func handlerErr(out string, err error) error { + if err != nil { + if out != "" { + return errors.New(out) + } + return err + } + return nil +} + +func run(name string, args ...string) (string, error) { + global.LOG.Debugf("handle with controller `%s %s`", name, strings.Join(args, " ")) + return cmd.NewCommandMgr(cmd.WithTimeout(10*time.Second)).RunWithStdoutBashCf("LANGUAGE=en_US:en %s %s", name, strings.Join(args, " ")) +} diff --git a/core/utils/controller/manager/openrc.go b/core/utils/controller/manager/openrc.go new file mode 100644 index 000000000..8f4492287 --- /dev/null +++ b/core/utils/controller/manager/openrc.go @@ -0,0 +1,61 @@ +package manager + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/1Panel-dev/1Panel/core/utils/cmd" +) + +type Openrc struct{ toolCmd string } + +func NewOpenrc() *Openrc { + return &Openrc{toolCmd: "rc-service"} +} + +func (s *Openrc) Name() string { + return "openrc" +} +func (s *Openrc) IsActive(serviceName string) (bool, error) { + out, err := cmd.RunDefaultWithStdoutBashCf("if service %s status >/dev/null 2>&1; then echo 'active'; else echo 'inactive'; fi", serviceName) + if err != nil { + return false, err + } + return out == "active\n", nil +} +func (s *Openrc) IsEnable(serviceName string) (bool, error) { + out, err := cmd.RunDefaultWithStdoutBashCf("if ls /etc/rc*.d/S*%s >/dev/null 2>&1; then echo 'enabled'; else echo 'disabled'; fi", serviceName) + if err != nil { + return false, err + } + return out == "enabled\n", nil +} +func (s *Openrc) IsExist(serviceName string) (bool, error) { + _, err := os.Stat(filepath.Join("/etc/init.d", serviceName)) + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, fmt.Errorf("stat /etc/init.d/%s failed: %w", serviceName, err) + } + return true, nil +} +func (s *Openrc) Status(serviceName string) (string, error) { + return run(s.toolCmd, serviceName, "status") +} + +func (s *Openrc) Operate(operate, serviceName string) error { + switch operate { + case "enable": + return handlerErr(run("rc-update", "add", serviceName, "default")) + case "disable": + return handlerErr(run("rc-update", "del", serviceName, "default")) + default: + return handlerErr(run(s.toolCmd, serviceName, operate)) + } +} + +func (s *Openrc) Reload() error { + return nil +} diff --git a/core/utils/controller/manager/snap.go b/core/utils/controller/manager/snap.go new file mode 100644 index 000000000..a4410ee9f --- /dev/null +++ b/core/utils/controller/manager/snap.go @@ -0,0 +1,54 @@ +package manager + +import ( + "strings" +) + +type Snap struct{ toolCmd string } + +func NewSnap() *Snap { + return &Snap{toolCmd: "snap"} +} + +func (s *Snap) IsExist(serviceName string) bool { + out, err := run(s.toolCmd, "services") + if err != nil { + return false + } + return strings.Contains(out, serviceName) +} + +func (s *Snap) IsActive(serviceName string) bool { + out, err := run(s.toolCmd, "services") + if err != nil { + return false + } + lines := strings.Split(out, "\n") + for _, line := range lines { + if strings.Contains(line, serviceName) && strings.Contains(line, "active") { + return true + } + } + return false +} + +func (s *Snap) IsEnable(serviceName string) bool { + out, err := run(s.toolCmd, "services") + if err != nil { + return false + } + lines := strings.Split(out, "\n") + for _, line := range lines { + if strings.Contains(line, serviceName) && strings.Contains(line, "enabled") { + return true + } + } + return false +} + +func (s *Snap) Operate(operate, serviceName string) error { + if s.IsExist(serviceName) { + return handlerErr(run(s.toolCmd, operate, serviceName)) + } + return nil +} diff --git a/core/utils/controller/manager/systemd.go b/core/utils/controller/manager/systemd.go new file mode 100644 index 000000000..8d6a2ecf7 --- /dev/null +++ b/core/utils/controller/manager/systemd.go @@ -0,0 +1,75 @@ +package manager + +import ( + "strings" +) + +type Systemd struct{ toolCmd string } + +func NewSystemd() *Systemd { + return &Systemd{toolCmd: "systemctl"} +} + +func (s *Systemd) Name() string { + return "systemd" +} +func (s *Systemd) IsActive(serviceName string) (bool, error) { + out, err := run(s.toolCmd, "is-active", serviceName) + if err != nil && out != "inactive\n" { + if NewSnap().IsActive(serviceName) { + return true, nil + } + return false, err + } + return out == "active\n", nil +} + +func (s *Systemd) IsEnable(serviceName string) (bool, error) { + out, err := run(s.toolCmd, "is-enabled", serviceName) + if err != nil && out != "disabled\n" { + if serviceName == "sshd" && out == "alias\n" { + return s.IsEnable("ssh") + } + if NewSnap().IsEnable(serviceName) { + return true, nil + } + return false, err + } + return out == "enabled\n", nil +} + +func (s *Systemd) IsExist(serviceName string) (bool, error) { + out, err := run(s.toolCmd, "is-enabled", serviceName) + if err != nil && out != "enabled\n" { + if strings.Contains(out, "disabled") { + return true, err + } + if NewSnap().IsExist(serviceName) { + return true, nil + } + return false, err + } + return true, err +} + +func (s *Systemd) Status(serviceName string) (string, error) { + return run(s.toolCmd, "status", serviceName) +} +func (s *Systemd) Operate(operate, serviceName string) error { + out, err := run(s.toolCmd, operate, serviceName) + if err != nil { + if serviceName == "sshd" && strings.Contains(out, "alias name or linked unit file") { + return s.Operate(operate, "ssh") + } + if err := NewSnap().Operate(operate, serviceName); err == nil { + return nil + } + return handlerErr(run(s.toolCmd, operate, serviceName)) + } + return nil +} + +func (s *Systemd) Reload() error { + out, err := run(s.toolCmd, "daemon-reload") + return handlerErr(out, err) +} diff --git a/core/utils/controller/manager/sysvinit.go b/core/utils/controller/manager/sysvinit.go new file mode 100644 index 000000000..2840911d3 --- /dev/null +++ b/core/utils/controller/manager/sysvinit.go @@ -0,0 +1,54 @@ +package manager + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/1Panel-dev/1Panel/core/utils/cmd" +) + +type Sysvinit struct{ toolCmd string } + +func NewSysvinit() *Sysvinit { + return &Sysvinit{toolCmd: "service"} +} + +func (s *Sysvinit) Name() string { + return "sysvinit" +} +func (s *Sysvinit) IsActive(serviceName string) (bool, error) { + out, err := cmd.RunDefaultWithStdoutBashCf("if service %s status >/dev/null 2>&1; then echo 'active'; else echo 'inactive'; fi", serviceName) + if err != nil { + return false, err + } + return out == "active\n", nil +} +func (s *Sysvinit) IsEnable(serviceName string) (bool, error) { + out, err := cmd.RunDefaultWithStdoutBashCf("if ls /etc/rc*.d/S*%s >/dev/null 2>&1; then echo 'enabled'; else echo 'disabled'; fi", serviceName) + if err != nil { + return false, err + } + return out == "enabled\n", nil +} +func (s *Sysvinit) IsExist(serviceName string) (bool, error) { + _, err := os.Stat(filepath.Join("/etc/init.d", serviceName)) + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, fmt.Errorf("stat /etc/init.d/%s failed: %w", serviceName, err) + } + return true, nil +} +func (s *Sysvinit) Status(serviceName string) (string, error) { + return run(s.toolCmd, serviceName, "status") +} + +func (s *Sysvinit) Operate(operate, serviceName string) error { + return handlerErr(run(s.toolCmd, serviceName, operate)) +} + +func (s *Sysvinit) Reload() error { + return nil +}