mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-17 21:08:25 +08:00
315 lines
7.9 KiB
Go
315 lines
7.9 KiB
Go
package controller
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"github.com/1Panel-dev/1Panel/core/global"
|
|
"github.com/1Panel-dev/1Panel/core/utils/controller/manager"
|
|
"github.com/1Panel-dev/1Panel/core/utils/ssh"
|
|
)
|
|
|
|
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{"systemctl", "rc-service", "service"}
|
|
for _, item := range managerOptions {
|
|
if _, err := exec.LookPath(item); err != nil {
|
|
continue
|
|
}
|
|
switch item {
|
|
case "systemctl":
|
|
return manager.NewSystemd(), nil
|
|
case "rc-service":
|
|
return manager.NewOpenrc(), nil
|
|
case "service":
|
|
return manager.NewSysvinit(), nil
|
|
}
|
|
}
|
|
return nil, errors.New("not support such manager initializatio")
|
|
}
|
|
|
|
func NewWithClient(client *ssh.SSHClient) (Controller, error) {
|
|
managerOptions := []string{"systemctl", "rc-service", "service"}
|
|
for _, item := range managerOptions {
|
|
stdout, err := client.Runf("which %s", item)
|
|
if err != nil || (len(strings.ReplaceAll(stdout, "\n", "")) == 0) {
|
|
continue
|
|
}
|
|
switch item {
|
|
case "systemctl":
|
|
mgr := manager.NewSystemd()
|
|
mgr.Client = client
|
|
return mgr, nil
|
|
case "rc-service":
|
|
mgr := manager.NewOpenrc()
|
|
mgr.Client = client
|
|
return mgr, nil
|
|
case "service":
|
|
mgr := manager.NewSysvinit()
|
|
mgr.Client = client
|
|
return mgr, 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, _ := 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-agent": {"1panel-agent.service"},
|
|
"docker": {"docker.service", "dockerd"},
|
|
}
|
|
if val, ok := predefinedMap[keyword]; ok {
|
|
for _, item := range val {
|
|
if exist, _ := mgr.IsExist(item); exist {
|
|
return item
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetServicePath returns the configuration file path for the specified service.
|
|
// If serviceName is empty, it returns the default directory path based on the system's service manager.
|
|
// For non-empty serviceName, it retrieves the exact service file path.
|
|
// Parameters:
|
|
// - serviceName: Name of the service. If empty, returns the default directory.
|
|
//
|
|
// Returns:
|
|
// - string: The service configuration file path.
|
|
// - error: Error if the service manager is unsupported or command execution fails.
|
|
func GetServicePath(serviceName string) (string, error) {
|
|
if serviceName == "" {
|
|
client, err := New()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
switch client.Name() {
|
|
case "systemd":
|
|
return "/etc/systemd/system/", nil
|
|
case "openrc", "sysvinit":
|
|
return "/etc/init.d/", nil
|
|
default:
|
|
return "", fmt.Errorf("unsupported manager: %s", client.Name())
|
|
}
|
|
}
|
|
service, err := LoadServiceName(serviceName)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
client, err := New()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
switch client.Name() {
|
|
case "systemd":
|
|
stdout, err := exec.Command("systemctl", "show", "-p", "FragmentPath", service).Output()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
parts := strings.SplitN(string(stdout), "=", 2)
|
|
if len(parts) != 2 {
|
|
return "", fmt.Errorf("unexpected output: %s", string(stdout))
|
|
}
|
|
return strings.TrimSpace(parts[1]), nil
|
|
case "openrc", "sysvinit":
|
|
return fmt.Sprintf("/etc/init.d/%s", service), nil
|
|
default:
|
|
return "", fmt.Errorf("unsupported manager: %s", client.Name())
|
|
}
|
|
}
|
|
|
|
func SelectInitScript(keyword string) (string, error) {
|
|
client, err := New()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
switch client.Name() {
|
|
case "systemd":
|
|
keyword = strings.TrimSuffix(keyword, ".service") + ".service"
|
|
case "openrc":
|
|
keyword = strings.TrimSuffix(keyword, ".service") + ".openrc"
|
|
case "sysvinit":
|
|
if _, err := os.Stat("/etc/rc.common"); err == nil {
|
|
keyword = strings.TrimSuffix(keyword, ".service") + ".prod"
|
|
} else {
|
|
keyword = strings.TrimSuffix(keyword, ".service") + ".init"
|
|
}
|
|
default:
|
|
return "", fmt.Errorf("unsupported manager: %s", client.Name())
|
|
}
|
|
return keyword, nil
|
|
}
|
|
|
|
func GetScriptName(keyword string) (string, error) {
|
|
client, err := New()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
switch client.Name() {
|
|
case "systemd":
|
|
keyword = strings.TrimSuffix(keyword, ".service") + ".service"
|
|
case "openrc", "sysvinit":
|
|
lastDotIdx := strings.LastIndex(keyword, ".")
|
|
if lastDotIdx != -1 {
|
|
keyword = keyword[:lastDotIdx]
|
|
}
|
|
default:
|
|
return "", fmt.Errorf("unsupported manager: %s", client.Name())
|
|
}
|
|
return keyword, nil
|
|
}
|