换成单集群模式

This commit is contained in:
robin
2026-03-02 20:07:53 +08:00
parent 5d0b7c7e91
commit 2a76d1773d
432 changed files with 5681 additions and 5095 deletions

View File

@@ -6,25 +6,107 @@ package utils
import (
"errors"
"os"
"os/exec"
"time"
teaconst "github.com/TeaOSLab/EdgeHttpDNS/internal/const"
executils "github.com/TeaOSLab/EdgeHttpDNS/internal/utils/exec"
"github.com/iwind/TeaGo/Tea"
)
var systemdServiceFile = "/etc/systemd/system/" + teaconst.SystemdServiceName + ".service"
var initServiceFile = "/etc/init.d/" + teaconst.SystemdServiceName
// Install 安装系统服务
func (m *ServiceManager) Install(exePath string, args []string) error {
if os.Getgid() != 0 {
return errors.New("only root users can install the service")
}
systemd, err := exec.LookPath("systemctl")
systemd, err := executils.LookPath("systemctl")
if err != nil {
return err
// systemd 不可用,降级到 init.d
return m.installInitService(exePath, args)
}
desc := `[Unit]
Description=GoEdge HTTPDNS Node Service
return m.installSystemdService(systemd, exePath, args)
}
// Start 启动服务
func (m *ServiceManager) Start() error {
if os.Getgid() != 0 {
return errors.New("only root users can start the service")
}
// 优先检查 systemd
if fileExists(systemdServiceFile) {
systemd, err := executils.LookPath("systemctl")
if err != nil {
return err
}
return executils.NewTimeoutCmd(10*time.Second, systemd, "start", teaconst.SystemdServiceName+".service").Start()
}
// 降级到 init.d
if fileExists(initServiceFile) {
return executils.NewTimeoutCmd(10*time.Second, "service", teaconst.ProcessName, "start").Start()
}
return errors.New("no service file found, please install the service first")
}
// Uninstall 删除服务
func (m *ServiceManager) Uninstall() error {
if os.Getgid() != 0 {
return errors.New("only root users can uninstall the service")
}
// systemd
if fileExists(systemdServiceFile) {
systemd, err := executils.LookPath("systemctl")
if err == nil {
_ = executils.NewTimeoutCmd(10*time.Second, systemd, "stop", teaconst.SystemdServiceName+".service").Run()
_ = executils.NewTimeoutCmd(10*time.Second, systemd, "disable", teaconst.SystemdServiceName+".service").Run()
_ = executils.NewTimeoutCmd(10*time.Second, systemd, "daemon-reload").Run()
}
return os.Remove(systemdServiceFile)
}
// init.d
if fileExists(initServiceFile) {
_ = executils.NewTimeoutCmd(10*time.Second, "service", teaconst.ProcessName, "stop").Run()
chkCmd, err := executils.LookPath("chkconfig")
if err == nil {
_ = executils.NewTimeoutCmd(10*time.Second, chkCmd, "--del", teaconst.ProcessName).Run()
}
return os.Remove(initServiceFile)
}
return nil
}
// installSystemdService 安装 systemd 服务
func (m *ServiceManager) installSystemdService(systemd, exePath string, args []string) error {
shortName := teaconst.SystemdServiceName
longName := "GoEdge HTTPDNS"
// 用 bash 包装启动命令,兼容路径含空格的场景
var startCmd = exePath + " daemon"
bashPath, _ := executils.LookPath("bash")
if len(bashPath) > 0 {
startCmd = bashPath + " -c \"" + startCmd + "\""
}
desc := `### BEGIN INIT INFO
# Provides: ` + shortName + `
# Required-Start: $all
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: ` + longName + ` Service
### END INIT INFO
[Unit]
Description=` + longName + ` Node Service
Before=shutdown.target
After=network-online.target
@@ -32,34 +114,102 @@ After=network-online.target
Type=simple
Restart=always
RestartSec=1s
ExecStart=` + exePath + ` daemon
ExecStart=` + startCmd + `
ExecStop=` + exePath + ` stop
ExecReload=` + exePath + ` restart
[Install]
WantedBy=multi-user.target`
err = os.WriteFile(systemdServiceFile, []byte(desc), 0777)
// 权限 0644systemd 单元文件不需要执行权限
err := os.WriteFile(systemdServiceFile, []byte(desc), 0644)
if err != nil {
return err
}
_ = exec.Command(systemd, "stop", teaconst.SystemdServiceName+".service").Run()
_ = exec.Command(systemd, "daemon-reload").Run()
return exec.Command(systemd, "enable", teaconst.SystemdServiceName+".service").Run()
// 停止已有服务
_ = executils.NewTimeoutCmd(10*time.Second, systemd, "stop", shortName+".service").Run()
// 重新加载
_ = executils.NewTimeoutCmd(10*time.Second, systemd, "daemon-reload").Run()
// 启用开机自启
return executils.NewTimeoutCmd(10*time.Second, systemd, "enable", shortName+".service").Run()
}
func (m *ServiceManager) Uninstall() error {
if os.Getgid() != 0 {
return errors.New("only root users can uninstall the service")
}
// installInitService 安装 init.d 服务(降级方案,适用于无 systemd 的旧系统)
func (m *ServiceManager) installInitService(exePath string, args []string) error {
shortName := teaconst.SystemdServiceName
longName := "GoEdge HTTPDNS"
systemd, err := exec.LookPath("systemctl")
// 生成 init.d 脚本
script := `#!/bin/bash
### BEGIN INIT INFO
# Provides: ` + shortName + `
# Required-Start: $all
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: ` + longName + ` Service
### END INIT INFO
INSTALL_DIR=` + Tea.Root + `
case "$1" in
start)
cd "${INSTALL_DIR}"
` + exePath + ` daemon &
echo "` + longName + ` started"
;;
stop)
cd "${INSTALL_DIR}"
` + exePath + ` stop
echo "` + longName + ` stopped"
;;
restart)
cd "${INSTALL_DIR}"
` + exePath + ` stop
sleep 1
` + exePath + ` daemon &
echo "` + longName + ` restarted"
;;
status)
cd "${INSTALL_DIR}"
` + exePath + ` status
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac
exit 0
`
// init.d 脚本需要执行权限
err := os.WriteFile(initServiceFile, []byte(script), 0755)
if err != nil {
return err
}
_ = exec.Command(systemd, "disable", teaconst.SystemdServiceName+".service").Run()
_ = exec.Command(systemd, "daemon-reload").Run()
return os.Remove(systemdServiceFile)
// 尝试用 chkconfig 注册CentOS/RHEL
chkCmd, err := executils.LookPath("chkconfig")
if err == nil {
_ = executils.NewTimeoutCmd(10*time.Second, chkCmd, "--add", teaconst.ProcessName).Run()
return nil
}
// 尝试用 update-rc.d 注册Debian/Ubuntu
updateRcCmd, err := executils.LookPath("update-rc.d")
if err == nil {
_ = executils.NewTimeoutCmd(10*time.Second, updateRcCmd, teaconst.ProcessName, "defaults").Run()
return nil
}
return nil
}
// fileExists 检查文件是否存在
func fileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}