mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-20 08:03:55 +08:00
feat: compatible with openrc and sysvinit (#10723)
This commit is contained in:
197
agent/utils/controller/controller.go
Normal file
197
agent/utils/controller/controller.go
Normal file
@@ -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 ""
|
||||
}
|
||||
25
agent/utils/controller/manager/common.go
Normal file
25
agent/utils/controller/manager/common.go
Normal file
@@ -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, " "))
|
||||
}
|
||||
61
agent/utils/controller/manager/openrc.go
Normal file
61
agent/utils/controller/manager/openrc.go
Normal file
@@ -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
|
||||
}
|
||||
54
agent/utils/controller/manager/snap.go
Normal file
54
agent/utils/controller/manager/snap.go
Normal 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
agent/utils/controller/manager/systemd.go
Normal file
75
agent/utils/controller/manager/systemd.go
Normal 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
agent/utils/controller/manager/sysvinit.go
Normal file
54
agent/utils/controller/manager/sysvinit.go
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user