feat: compatible with openrc and sysvinit (#10723)

This commit is contained in:
ssongliu
2025-10-22 18:32:42 +08:00
committed by GitHub
parent f462591e9c
commit c06ba18023
50 changed files with 1310 additions and 687 deletions
+5 -16
View File
@@ -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 {
+2 -5
View File
@@ -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
}
+2 -5
View File
@@ -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
},
}
+6 -9
View File
@@ -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")
+197
View File
@@ -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 ""
}
+25
View File
@@ -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, " "))
}
+61
View File
@@ -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
}
+54
View File
@@ -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
}
+75
View File
@@ -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)
}
+54
View File
@@ -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
}