2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 09:13:49 +08:00

refactor: 重构shell命令执行

This commit is contained in:
耗子
2024-06-23 00:44:14 +08:00
parent aa9b55d1eb
commit 11d6b40dce
29 changed files with 476 additions and 352 deletions

View File

@@ -17,6 +17,7 @@ import (
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/internal/services"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -143,7 +144,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
return nil
}
port, err := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
port, err := shell.Execf(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
if err != nil {
color.Red().Printfln(translate.Get("commands.panel.portFail"))
return nil
@@ -164,7 +165,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
color.Green().Printfln(translate.Get("commands.panel.getInfo.address") + ": " + protocol + "://" + ip + ":" + port + facades.Config().GetString("http.entrance"))
case "getPort":
port, err := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
port, err := shell.Execf(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
if err != nil {
color.Red().Printfln(translate.Get("commands.panel.portFail"))
return nil
@@ -176,12 +177,12 @@ func (receiver *Panel) Handle(ctx console.Context) error {
color.Green().Printfln(translate.Get("commands.panel.entrance") + ": " + facades.Config().GetString("http.entrance"))
case "deleteEntrance":
oldEntrance, err := tools.Exec(`cat /www/panel/panel.conf | grep APP_ENTRANCE | awk -F '=' '{print $2}' | tr -d '\n'`)
oldEntrance, err := shell.Execf(`cat /www/panel/panel.conf | grep APP_ENTRANCE | awk -F '=' '{print $2}' | tr -d '\n'`)
if err != nil {
color.Red().Printfln(translate.Get("commands.panel.deleteEntrance.fail"))
return nil
}
if _, err = tools.Exec("sed -i 's!APP_ENTRANCE=" + oldEntrance + "!APP_ENTRANCE=/!g' /www/panel/panel.conf"); err != nil {
if _, err = shell.Execf("sed -i 's!APP_ENTRANCE=" + oldEntrance + "!APP_ENTRANCE=/!g' /www/panel/panel.conf"); err != nil {
color.Red().Printfln(translate.Get("commands.panel.deleteEntrance.fail"))
return nil
}
@@ -288,7 +289,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
}
backupFile := path + "/" + website.Name + "_" + carbon.Now().ToShortDateTimeString() + ".zip"
if _, err := tools.Exec(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`); err != nil {
if _, err := shell.Execf(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`); err != nil {
color.Red().Printfln("|-" + translate.Get("commands.panel.backup.backupFail") + ": " + err.Error())
return nil
}
@@ -307,13 +308,13 @@ func (receiver *Panel) Handle(ctx console.Context) error {
color.Green().Printfln("|-" + translate.Get("commands.panel.backup.targetMysql") + ": " + name)
color.Green().Printfln("|-" + translate.Get("commands.panel.backup.startExport"))
if _, err = tools.Exec(`mysqldump -uroot ` + name + ` > /tmp/` + backupFile + ` 2>&1`); err != nil {
if _, err = shell.Execf(`mysqldump -uroot ` + name + ` > /tmp/` + backupFile + ` 2>&1`); err != nil {
color.Red().Printfln("|-" + translate.Get("commands.panel.backup.exportFail") + ": " + err.Error())
return nil
}
color.Green().Printfln("|-" + translate.Get("commands.panel.backup.exportSuccess"))
color.Green().Printfln("|-" + translate.Get("commands.panel.backup.startCompress"))
if _, err = tools.Exec("cd /tmp && zip -r " + backupFile + ".zip " + backupFile); err != nil {
if _, err = shell.Execf("cd /tmp && zip -r " + backupFile + ".zip " + backupFile); err != nil {
color.Red().Printfln("|-" + translate.Get("commands.panel.backup.compressFail") + ": " + err.Error())
return nil
}
@@ -333,7 +334,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
case "postgresql":
backupFile := name + "_" + carbon.Now().ToShortDateTimeString() + ".sql"
check, err := tools.Exec(`su - postgres -c "psql -l" 2>&1`)
check, err := shell.Execf(`su - postgres -c "psql -l" 2>&1`)
if err != nil {
color.Red().Printfln("|-" + translate.Get("commands.panel.backup.databaseGetFail") + ": " + err.Error())
color.Green().Printfln(hr)
@@ -347,13 +348,13 @@ func (receiver *Panel) Handle(ctx console.Context) error {
color.Green().Printfln("|-" + translate.Get("commands.panel.backup.targetPostgres") + ": " + name)
color.Green().Printfln("|-" + translate.Get("commands.panel.backup.startExport"))
if _, err = tools.Exec(`su - postgres -c "pg_dump '` + name + `'" > /tmp/` + backupFile + ` 2>&1`); err != nil {
if _, err = shell.Execf(`su - postgres -c "pg_dump '` + name + `'" > /tmp/` + backupFile + ` 2>&1`); err != nil {
color.Red().Printfln("|-" + translate.Get("commands.panel.backup.exportFail") + ": " + err.Error())
return nil
}
color.Green().Printfln("|-" + translate.Get("commands.panel.backup.exportSuccess"))
color.Green().Printfln("|-" + translate.Get("commands.panel.backup.startCompress"))
if _, err = tools.Exec("cd /tmp && zip -r " + backupFile + ".zip " + backupFile); err != nil {
if _, err = shell.Execf("cd /tmp && zip -r " + backupFile + ".zip " + backupFile); err != nil {
color.Red().Printfln("|-" + translate.Get("commands.panel.backup.compressFail") + ": " + err.Error())
return nil
}
@@ -432,11 +433,11 @@ func (receiver *Panel) Handle(ctx console.Context) error {
}
backupPath := "/www/wwwlogs/" + website.Name + "_" + carbon.Now().ToShortDateTimeString() + ".log.zip"
if _, err := tools.Exec(`cd /www/wwwlogs && zip -r ` + backupPath + ` ` + website.Name + ".log"); err != nil {
if _, err := shell.Execf(`cd /www/wwwlogs && zip -r ` + backupPath + ` ` + website.Name + ".log"); err != nil {
color.Red().Printfln("|-" + translate.Get("commands.panel.cutoff.backupFail") + ": " + err.Error())
return nil
}
if _, err := tools.Exec(`echo "" > ` + logPath); err != nil {
if _, err := shell.Execf(`echo "" > ` + logPath); err != nil {
color.Red().Printfln("|-" + translate.Get("commands.panel.cutoff.clearFail") + ": " + err.Error())
return nil
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/goravel/framework/facades"
"github.com/goravel/framework/support/carbon"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -58,7 +59,7 @@ func (receiver *PanelTask) Handle(console.Context) error {
}
// 清理 7 天前的备份
if _, err := tools.Exec(`find /www/backup/panel -mtime +7 -name "*.zip" -exec rm -rf {} \;`); err != nil {
if _, err := shell.Execf(`find /www/backup/panel -mtime +7 -name "*.zip" -exec rm -rf {} \;`); err != nil {
types.Status = types.StatusFailed
facades.Log().Tags("面板", "每日任务").
With(map[string]any{

View File

@@ -12,6 +12,7 @@ import (
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/internal"
"github.com/TheTNB/panel/internal/services"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
)
@@ -65,7 +66,7 @@ func (r *CronController) Add(ctx http.Context) http.Response {
return Error(ctx, http.StatusUnprocessableEntity, "时间格式错误")
}
shell := ctx.Request().Input("script")
script := ctx.Request().Input("script")
cronType := ctx.Request().Input("type")
if cronType == "backup" {
backupType := ctx.Request().Input("backup_type")
@@ -78,7 +79,7 @@ func (r *CronController) Add(ctx http.Context) http.Response {
backupPath = r.setting.Get(models.SettingKeyBackupPath) + "/" + backupType
}
backupSave := ctx.Request().InputInt("save", 10)
shell = `#!/bin/bash
script = `#!/bin/bash
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
# 耗子面板 - 数据备份脚本
@@ -95,7 +96,7 @@ panel backup ${type} ${name} ${path} ${save} 2>&1
if cronType == "cutoff" {
website := ctx.Request().Input("website")
save := ctx.Request().InputInt("save", 180)
shell = `#!/bin/bash
script = `#!/bin/bash
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
# 耗子面板 - 日志切割脚本
@@ -117,10 +118,10 @@ panel cutoff ${name} ${save} 2>&1
return Error(ctx, http.StatusInternalServerError, "计划任务日志目录不存在")
}
shellFile := strconv.Itoa(int(carbon.Now().Timestamp())) + tools.RandomString(16)
if err := tools.Write(shellDir+shellFile+".sh", shell, 0700); err != nil {
if err := tools.Write(shellDir+shellFile+".sh", script, 0700); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
if out, err := tools.Exec("dos2unix " + shellDir + shellFile + ".sh"); err != nil {
if out, err := shell.Execf("dos2unix " + shellDir + shellFile + ".sh"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
@@ -156,12 +157,12 @@ func (r *CronController) Script(ctx http.Context) http.Response {
return Error(ctx, http.StatusUnprocessableEntity, "计划任务不存在")
}
shell, err := tools.Read(cron.Shell)
script, err := tools.Read(cron.Shell)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
return Success(ctx, shell)
return Success(ctx, script)
}
// Update 更新计划任务
@@ -200,7 +201,7 @@ func (r *CronController) Update(ctx http.Context) http.Response {
if err := tools.Write(cron.Shell, ctx.Request().Input("script"), 0644); err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}
if out, err := tools.Exec("dos2unix " + cron.Shell); err != nil {
if out, err := shell.Execf("dos2unix " + cron.Shell); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
@@ -284,7 +285,7 @@ func (r *CronController) Log(ctx http.Context) http.Response {
return Error(ctx, http.StatusUnprocessableEntity, "日志文件不存在")
}
log, err := tools.Exec("tail -n 1000 " + cron.Log)
log, err := shell.Execf("tail -n 1000 " + cron.Log)
if err != nil {
return Error(ctx, http.StatusInternalServerError, err.Error())
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/goravel/framework/support/carbon"
requests "github.com/TheTNB/panel/app/http/requests/file"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
)
@@ -42,7 +43,7 @@ func (r *FileController) Create(ctx http.Context) http.Response {
isDir := ctx.Request().InputBool("dir")
if !isDir {
if out, err := tools.Exec("touch " + request.Path); err != nil {
if out, err := shell.Execf("touch " + request.Path); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
} else {

View File

@@ -12,6 +12,7 @@ import (
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/internal"
"github.com/TheTNB/panel/internal/services"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -152,7 +153,7 @@ func (r *InfoController) CountInfo(ctx http.Context) http.Response {
if postgresqlInstalled {
status, err := tools.ServiceStatus("postgresql")
if status && err == nil {
raw, err := tools.Exec(`echo "\l" | su - postgres -c "psql"`)
raw, err := shell.Execf(`echo "\l" | su - postgres -c "psql"`)
if err == nil {
databases := strings.Split(raw, "\n")
if len(databases) >= 4 {
@@ -173,7 +174,7 @@ func (r *InfoController) CountInfo(ctx http.Context) http.Response {
var ftpCount int64
var ftpPlugin = r.plugin.GetInstalledBySlug("pureftpd")
if ftpPlugin.ID != 0 {
listRaw, err := tools.Exec("pure-pw list")
listRaw, err := shell.Execf("pure-pw list")
if len(listRaw) != 0 && err == nil {
listArr := strings.Split(listRaw, "\n")
ftpCount = int64(len(listArr))

View File

@@ -12,6 +12,7 @@ import (
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/internal"
"github.com/TheTNB/panel/internal/services"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -171,15 +172,15 @@ ignoreregex =
logPath = "/var/log/secure"
}
filter = "sshd"
port, err = tools.Exec("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
port, err = shell.Execf("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
case "mysql":
logPath = "/www/server/mysql/mysql-error.log"
filter = "mysqld-auth"
port, err = tools.Exec("cat /www/server/mysql/conf/my.cnf | grep 'port' | head -n 1 | awk '{print $3}'")
port, err = shell.Execf("cat /www/server/mysql/conf/my.cnf | grep 'port' | head -n 1 | awk '{print $3}'")
case "pure-ftpd":
logPath = "/var/log/messages"
filter = "pure-ftpd"
port, err = tools.Exec(`cat /www/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`)
port, err = shell.Execf(`cat /www/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`)
default:
return controllers.Error(ctx, http.StatusUnprocessableEntity, "未知服务")
}
@@ -206,7 +207,7 @@ logpath = ` + logPath + `
}
}
if _, err := tools.Exec("fail2ban-client reload"); err != nil {
if _, err := shell.Execf("fail2ban-client reload"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "重载配置失败")
}
@@ -231,7 +232,7 @@ func (r *Fail2banController) Delete(ctx http.Context) http.Response {
return controllers.Error(ctx, http.StatusInternalServerError, "写入Fail2ban规则失败")
}
if _, err := tools.Exec("fail2ban-client reload"); err != nil {
if _, err := shell.Execf("fail2ban-client reload"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "重载配置失败")
}
@@ -245,15 +246,15 @@ func (r *Fail2banController) BanList(ctx http.Context) http.Response {
return controllers.Error(ctx, http.StatusUnprocessableEntity, "缺少参数")
}
currentlyBan, err := tools.Exec(`fail2ban-client status ` + name + ` | grep "Currently banned" | awk '{print $4}'`)
currentlyBan, err := shell.Execf(`fail2ban-client status %s | grep "Currently banned" | awk '{print $4}'`, name)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取封禁列表失败")
}
totalBan, err := tools.Exec(`fail2ban-client status ` + name + ` | grep "Total banned" | awk '{print $4}'`)
totalBan, err := shell.Execf(`fail2ban-client status %s | grep "Total banned" | awk '{print $4}'`, name)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取封禁列表失败")
}
bannedIp, err := tools.Exec(`fail2ban-client status ` + name + ` | grep "Banned IP list" | awk -F ":" '{print $2}'`)
bannedIp, err := shell.Execf(`fail2ban-client status %s | grep "Banned IP list" | awk -F ":" '{print $2}'`, name)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取封禁列表失败")
}
@@ -287,7 +288,7 @@ func (r *Fail2banController) Unban(ctx http.Context) http.Response {
return controllers.Error(ctx, http.StatusUnprocessableEntity, "缺少参数")
}
if _, err := tools.Exec("fail2ban-client set " + name + " unbanip " + ip); err != nil {
if _, err := shell.Execf("fail2ban-client set %s unbanip %s", name, ip); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "解封失败")
}
@@ -317,7 +318,7 @@ func (r *Fail2banController) SetWhiteList(ctx http.Context) http.Response {
return controllers.Error(ctx, http.StatusInternalServerError, "写入Fail2ban规则失败")
}
if _, err := tools.Exec("fail2ban-client reload"); err != nil {
if _, err := shell.Execf("fail2ban-client reload"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "重载配置失败")
}
return controllers.Success(ctx, nil)

View File

@@ -12,6 +12,7 @@ import (
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/internal"
"github.com/TheTNB/panel/internal/services"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -68,7 +69,7 @@ func (r *MySQLController) Load(ctx http.Context) http.Response {
return controllers.Success(ctx, []types.NV{})
}
raw, err := tools.Exec("/www/server/mysql/bin/mysqladmin -uroot -p" + rootPassword + " extended-status 2>&1")
raw, err := shell.Execf("/www/server/mysql/bin/mysqladmin -uroot -p" + rootPassword + " extended-status 2>&1")
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL负载失败")
}
@@ -125,7 +126,7 @@ func (r *MySQLController) Load(ctx http.Context) http.Response {
// ErrorLog 获取错误日志
func (r *MySQLController) ErrorLog(ctx http.Context) http.Response {
log, err := tools.Exec("tail -n 100 /www/server/mysql/mysql-error.log")
log, err := shell.Execf("tail -n 100 /www/server/mysql/mysql-error.log")
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, log)
}
@@ -135,7 +136,7 @@ func (r *MySQLController) ErrorLog(ctx http.Context) http.Response {
// ClearErrorLog 清空错误日志
func (r *MySQLController) ClearErrorLog(ctx http.Context) http.Response {
if out, err := tools.Exec("echo '' > /www/server/mysql/mysql-error.log"); err != nil {
if out, err := shell.Execf("echo '' > /www/server/mysql/mysql-error.log"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -144,7 +145,7 @@ func (r *MySQLController) ClearErrorLog(ctx http.Context) http.Response {
// SlowLog 获取慢查询日志
func (r *MySQLController) SlowLog(ctx http.Context) http.Response {
log, err := tools.Exec("tail -n 100 /www/server/mysql/mysql-slow.log")
log, err := shell.Execf("tail -n 100 /www/server/mysql/mysql-slow.log")
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, log)
}
@@ -154,7 +155,7 @@ func (r *MySQLController) SlowLog(ctx http.Context) http.Response {
// ClearSlowLog 清空慢查询日志
func (r *MySQLController) ClearSlowLog(ctx http.Context) http.Response {
if out, err := tools.Exec("echo '' > /www/server/mysql/mysql-slow.log"); err != nil {
if out, err := shell.Execf("echo '' > /www/server/mysql/mysql-slow.log"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
return controllers.Success(ctx, nil)
@@ -187,15 +188,15 @@ func (r *MySQLController) SetRootPassword(ctx http.Context) http.Response {
oldRootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword)
if oldRootPassword != rootPassword {
if _, err = tools.Exec(fmt.Sprintf(`/www/server/mysql/bin/mysql -uroot -p%s -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '%s';"`, oldRootPassword, rootPassword)); err != nil {
if _, err = shell.Execf(fmt.Sprintf(`/www/server/mysql/bin/mysql -uroot -p%s -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '%s';"`, oldRootPassword, rootPassword)); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, fmt.Sprintf("设置root密码失败: %v", err))
}
if _, err = tools.Exec(fmt.Sprintf(`/www/server/mysql/bin/mysql -uroot -p%s -e "FLUSH PRIVILEGES;"`, rootPassword)); err != nil {
if _, err = shell.Execf(fmt.Sprintf(`/www/server/mysql/bin/mysql -uroot -p%s -e "FLUSH PRIVILEGES;"`, rootPassword)); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "设置root密码失败")
}
if err = r.setting.Set(models.SettingKeyMysqlRootPassword, rootPassword); err != nil {
_, _ = tools.Exec(fmt.Sprintf(`/www/server/mysql/bin/mysql -uroot -p%s -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '%s';"`, rootPassword, oldRootPassword))
_, _ = tools.Exec(fmt.Sprintf(`/www/server/mysql/bin/mysql -uroot -p%s -e "FLUSH PRIVILEGES;"`, oldRootPassword))
_, _ = shell.Execf(fmt.Sprintf(`/www/server/mysql/bin/mysql -uroot -p%s -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '%s';"`, rootPassword, oldRootPassword))
_, _ = shell.Execf(fmt.Sprintf(`/www/server/mysql/bin/mysql -uroot -p%s -e "FLUSH PRIVILEGES;"`, oldRootPassword))
return controllers.Error(ctx, http.StatusInternalServerError, fmt.Sprintf("设置保存失败: %v", err))
}
}
@@ -269,16 +270,16 @@ func (r *MySQLController) AddDatabase(ctx http.Context) http.Response {
user := ctx.Request().Input("user")
password := ctx.Request().Input("password")
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE DATABASE IF NOT EXISTS " + database + " DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE DATABASE IF NOT EXISTS " + database + " DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -295,7 +296,7 @@ func (r *MySQLController) DeleteDatabase(ctx http.Context) http.Response {
rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword)
database := ctx.Request().Input("database")
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP DATABASE IF EXISTS " + database + ";\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP DATABASE IF EXISTS " + database + ";\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -477,13 +478,13 @@ func (r *MySQLController) AddUser(ctx http.Context) http.Response {
user := ctx.Request().Input("user")
password := ctx.Request().Input("password")
database := ctx.Request().Input("database")
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + ";'\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + ";'\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -500,7 +501,7 @@ func (r *MySQLController) DeleteUser(ctx http.Context) http.Response {
rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword)
user := ctx.Request().Input("user")
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP USER '" + user + "'@'localhost';\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP USER '" + user + "'@'localhost';\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -519,10 +520,10 @@ func (r *MySQLController) SetUserPassword(ctx http.Context) http.Response {
rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword)
user := ctx.Request().Input("user")
password := ctx.Request().Input("password")
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -541,13 +542,13 @@ func (r *MySQLController) SetUserPrivileges(ctx http.Context) http.Response {
rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword)
user := ctx.Request().Input("user")
database := ctx.Request().Input("database")
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"REVOKE ALL PRIVILEGES ON *.* FROM '" + user + "'@'localhost';\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"REVOKE ALL PRIVILEGES ON *.* FROM '" + user + "'@'localhost';\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil {
if out, err := shell.Execf("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/spf13/cast"
"github.com/TheTNB/panel/app/http/controllers"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -77,7 +78,7 @@ func (r *OpenRestyController) ErrorLog(ctx http.Context) http.Response {
return controllers.Success(ctx, "")
}
out, err := tools.Exec("tail -n 100 /www/wwwlogs/openresty_error.log")
out, err := shell.Execf("tail -n 100 /www/wwwlogs/openresty_error.log")
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -94,7 +95,7 @@ func (r *OpenRestyController) ErrorLog(ctx http.Context) http.Response {
// @Success 200 {object} controllers.SuccessResponse
// @Router /plugins/openresty/clearErrorLog [post]
func (r *OpenRestyController) ClearErrorLog(ctx http.Context) http.Response {
if out, err := tools.Exec("echo '' > /www/wwwlogs/openresty_error.log"); err != nil {
if out, err := shell.Execf("echo '' > /www/wwwlogs/openresty_error.log"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -119,7 +120,7 @@ func (r *OpenRestyController) Load(ctx http.Context) http.Response {
raw := resp.String()
var data []types.NV
workers, err := tools.Exec("ps aux | grep nginx | grep 'worker process' | wc -l")
workers, err := shell.Execf("ps aux | grep nginx | grep 'worker process' | wc -l")
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取负载失败")
}
@@ -128,7 +129,7 @@ func (r *OpenRestyController) Load(ctx http.Context) http.Response {
Value: workers,
})
out, err := tools.Exec("ps aux | grep nginx | grep 'worker process' | awk '{memsum+=$6};END {print memsum}'")
out, err := shell.Execf("ps aux | grep nginx | grep 'worker process' | awk '{memsum+=$6};END {print memsum}'")
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取负载失败")
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/spf13/cast"
"github.com/TheTNB/panel/app/http/controllers"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
)
@@ -52,8 +53,8 @@ func (r *PhpMyAdminController) Info(ctx http.Context) http.Response {
}
func (r *PhpMyAdminController) SetPort(ctx http.Context) http.Response {
port := ctx.Request().Input("port")
if len(port) == 0 {
port := ctx.Request().InputInt("port")
if port == 0 {
return controllers.Error(ctx, http.StatusInternalServerError, "端口不能为空")
}
@@ -61,7 +62,7 @@ func (r *PhpMyAdminController) SetPort(ctx http.Context) http.Response {
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
}
conf = regexp.MustCompile(`listen\s+(\d+);`).ReplaceAllString(conf, "listen "+port+";")
conf = regexp.MustCompile(`listen\s+(\d+);`).ReplaceAllString(conf, "listen "+cast.ToString(port)+";")
if err := tools.Write("/www/server/vhost/phpmyadmin.conf", conf, 0644); err != nil {
facades.Log().Request(ctx.Request()).Tags("插件", "phpMyAdmin").With(map[string]any{
"error": err.Error(),
@@ -70,17 +71,17 @@ func (r *PhpMyAdminController) SetPort(ctx http.Context) http.Response {
}
if tools.IsRHEL() {
if out, err := tools.Exec("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent"); err != nil {
if out, err := shell.Execf("firewall-cmd --zone=public --add-port=%d/tcp --permanent", port); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("firewall-cmd --reload"); err != nil {
if out, err := shell.Execf("firewall-cmd --reload"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
} else {
if out, err := tools.Exec("ufw allow " + port + "/tcp"); err != nil {
if out, err := shell.Execf("ufw allow %d/tcp", port); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("ufw reload"); err != nil {
if out, err := shell.Execf("ufw reload"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/internal"
"github.com/TheTNB/panel/internal/services"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -92,23 +93,23 @@ func (r *PostgreSQLController) Load(ctx http.Context) http.Response {
return controllers.Success(ctx, []types.NV{})
}
time, err := tools.Exec(`echo "select pg_postmaster_start_time();" | su - postgres -c "psql" | sed -n 3p | cut -d'.' -f1`)
time, err := shell.Execf(`echo "select pg_postmaster_start_time();" | su - postgres -c "psql" | sed -n 3p | cut -d'.' -f1`)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL启动时间失败")
}
pid, err := tools.Exec(`echo "select pg_backend_pid();" | su - postgres -c "psql" | sed -n 3p`)
pid, err := shell.Execf(`echo "select pg_backend_pid();" | su - postgres -c "psql" | sed -n 3p`)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL进程PID失败")
}
process, err := tools.Exec(`ps aux | grep postgres | grep -v grep | wc -l`)
process, err := shell.Execf(`ps aux | grep postgres | grep -v grep | wc -l`)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL进程数失败")
}
connections, err := tools.Exec(`echo "SELECT count(*) FROM pg_stat_activity WHERE NOT pid=pg_backend_pid();" | su - postgres -c "psql" | sed -n 3p`)
connections, err := shell.Execf(`echo "SELECT count(*) FROM pg_stat_activity WHERE NOT pid=pg_backend_pid();" | su - postgres -c "psql" | sed -n 3p`)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL连接数失败")
}
storage, err := tools.Exec(`echo "select pg_size_pretty(pg_database_size('postgres'));" | su - postgres -c "psql" | sed -n 3p`)
storage, err := shell.Execf(`echo "select pg_size_pretty(pg_database_size('postgres'));" | su - postgres -c "psql" | sed -n 3p`)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL空间占用失败")
}
@@ -126,7 +127,7 @@ func (r *PostgreSQLController) Load(ctx http.Context) http.Response {
// Log 获取日志
func (r *PostgreSQLController) Log(ctx http.Context) http.Response {
log, err := tools.Exec("tail -n 100 /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log")
log, err := shell.Execf("tail -n 100 /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log")
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, log)
}
@@ -136,7 +137,7 @@ func (r *PostgreSQLController) Log(ctx http.Context) http.Response {
// ClearLog 清空日志
func (r *PostgreSQLController) ClearLog(ctx http.Context) http.Response {
if out, err := tools.Exec("echo '' > /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log"); err != nil {
if out, err := shell.Execf("echo '' > /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -211,21 +212,21 @@ func (r *PostgreSQLController) AddDatabase(ctx http.Context) http.Response {
user := ctx.Request().Input("user")
password := ctx.Request().Input("password")
if out, err := tools.Exec(`echo "CREATE DATABASE ` + database + `;" | su - postgres -c "psql"`); err != nil {
if out, err := shell.Execf(`echo "CREATE DATABASE ` + database + `;" | su - postgres -c "psql"`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec(`echo "CREATE USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`); err != nil {
if out, err := shell.Execf(`echo "CREATE USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec(`echo "ALTER DATABASE ` + database + ` OWNER TO ` + user + `;" | su - postgres -c "psql"`); err != nil {
if out, err := shell.Execf(`echo "ALTER DATABASE ` + database + ` OWNER TO ` + user + `;" | su - postgres -c "psql"`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`); err != nil {
if out, err := shell.Execf(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
userConfig := "host " + database + " " + user + " 127.0.0.1/32 scram-sha-256"
if out, err := tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`); err != nil {
if out, err := shell.Execf(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -245,7 +246,7 @@ func (r *PostgreSQLController) DeleteDatabase(ctx http.Context) http.Response {
}
database := ctx.Request().Input("database")
if out, err := tools.Exec(`echo "DROP DATABASE ` + database + `;" | su - postgres -c "psql"`); err != nil {
if out, err := shell.Execf(`echo "DROP DATABASE ` + database + `;" | su - postgres -c "psql"`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -428,15 +429,15 @@ func (r *PostgreSQLController) AddRole(ctx http.Context) http.Response {
user := ctx.Request().Input("user")
password := ctx.Request().Input("password")
database := ctx.Request().Input("database")
if out, err := tools.Exec(`echo "CREATE USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`); err != nil {
if out, err := shell.Execf(`echo "CREATE USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`); err != nil {
if out, err := shell.Execf(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
userConfig := "host " + database + " " + user + " 127.0.0.1/32 scram-sha-256"
if out, err := tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`); err != nil {
if out, err := shell.Execf(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -456,10 +457,10 @@ func (r *PostgreSQLController) DeleteRole(ctx http.Context) http.Response {
}
user := ctx.Request().Input("user")
if out, err := tools.Exec(`echo "DROP USER ` + user + `;" | su - postgres -c "psql"`); err != nil {
if out, err := shell.Execf(`echo "DROP USER ` + user + `;" | su - postgres -c "psql"`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec(`sed -i '/` + user + `/d' /www/server/postgresql/data/pg_hba.conf`); err != nil {
if out, err := shell.Execf(`sed -i '/` + user + `/d' /www/server/postgresql/data/pg_hba.conf`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -481,7 +482,7 @@ func (r *PostgreSQLController) SetRolePassword(ctx http.Context) http.Response {
user := ctx.Request().Input("user")
password := ctx.Request().Input("password")
if out, err := tools.Exec(`echo "ALTER USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`); err != nil {
if out, err := shell.Execf(`echo "ALTER USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/spf13/cast"
"github.com/TheTNB/panel/app/http/controllers"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -21,7 +22,7 @@ func NewPureFtpdController() *PureFtpdController {
// List 获取用户列表
func (r *PureFtpdController) List(ctx http.Context) http.Response {
listRaw, err := tools.Exec("pure-pw list")
listRaw, err := shell.Execf("pure-pw list")
if err != nil {
return controllers.Success(ctx, http.Json{
"total": 0,
@@ -78,10 +79,10 @@ func (r *PureFtpdController) Add(ctx http.Context) http.Response {
if err := tools.Chown(path, "www", "www"); err != nil {
return nil
}
if out, err := tools.Exec(`yes '` + password + `' | pure-pw useradd ` + username + ` -u www -g www -d ` + path); err != nil {
if out, err := shell.Execf(`yes '` + password + `' | pure-pw useradd ` + username + ` -u www -g www -d ` + path); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("pure-pw mkdb"); err != nil {
if out, err := shell.Execf("pure-pw mkdb"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -98,10 +99,10 @@ func (r *PureFtpdController) Delete(ctx http.Context) http.Response {
username := ctx.Request().Input("username")
if out, err := tools.Exec("pure-pw userdel " + username + " -m"); err != nil {
if out, err := shell.Execf("pure-pw userdel " + username + " -m"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("pure-pw mkdb"); err != nil {
if out, err := shell.Execf("pure-pw mkdb"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -120,10 +121,10 @@ func (r *PureFtpdController) ChangePassword(ctx http.Context) http.Response {
username := ctx.Request().Input("username")
password := ctx.Request().Input("password")
if out, err := tools.Exec(`yes '` + password + `' | pure-pw passwd ` + username + ` -m`); err != nil {
if out, err := shell.Execf(`yes '` + password + `' | pure-pw passwd ` + username + ` -m`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("pure-pw mkdb"); err != nil {
if out, err := shell.Execf("pure-pw mkdb"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -132,7 +133,7 @@ func (r *PureFtpdController) ChangePassword(ctx http.Context) http.Response {
// GetPort 获取端口
func (r *PureFtpdController) GetPort(ctx http.Context) http.Response {
port, err := tools.Exec(`cat /www/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`)
port, err := shell.Execf(`cat /www/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd端口失败")
}
@@ -149,21 +150,21 @@ func (r *PureFtpdController) SetPort(ctx http.Context) http.Response {
}
port := ctx.Request().Input("port")
if out, err := tools.Exec(`sed -i "s/Bind.*/Bind 0.0.0.0,` + port + `/g" /www/server/pure-ftpd/etc/pure-ftpd.conf`); err != nil {
if out, err := shell.Execf(`sed -i "s/Bind.*/Bind 0.0.0.0,%s/g" /www/server/pure-ftpd/etc/pure-ftpd.conf`, port); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if tools.IsRHEL() {
if out, err := tools.Exec("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent"); err != nil {
if out, err := shell.Execf("firewall-cmd --zone=public --add-port=%s/tcp --permanent", port); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("firewall-cmd --reload"); err != nil {
if out, err := shell.Execf("firewall-cmd --reload"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
} else {
if out, err := tools.Exec("ufw allow " + port + "/tcp"); err != nil {
if out, err := shell.Execf("ufw allow %s/tcp", port); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("ufw reload"); err != nil {
if out, err := shell.Execf("ufw reload"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/goravel/framework/contracts/http"
"github.com/TheTNB/panel/app/http/controllers"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -56,7 +57,7 @@ func (r *RedisController) Load(ctx http.Context) http.Response {
return controllers.Error(ctx, http.StatusInternalServerError, "Redis已停止运行")
}
raw, err := tools.Exec("redis-cli info")
raw, err := shell.Execf("redis-cli info")
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取Redis负载失败")
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/TheTNB/panel/app/http/controllers"
requests "github.com/TheTNB/panel/app/http/requests/plugins/rsync"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -69,7 +70,7 @@ func (r *RsyncController) List(ctx http.Context) http.Response {
currentModule.ReadOnly = value == "yes" || value == "true"
case "auth users":
currentModule.AuthUser = value
currentModule.Secret, err = tools.Exec("grep -E '^" + currentModule.AuthUser + ":.*$' /etc/rsyncd.secrets | awk -F ':' '{print $2}'")
currentModule.Secret, err = shell.Execf("grep -E '^" + currentModule.AuthUser + ":.*$' /etc/rsyncd.secrets | awk -F ':' '{print $2}'")
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "获取模块"+currentModule.AuthUser+"的密钥失败")
}
@@ -131,7 +132,7 @@ secrets file = /etc/rsyncd.secrets
if err := tools.WriteAppend("/etc/rsyncd.conf", conf); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
}
if out, err := tools.Exec("echo '" + createRequest.AuthUser + ":" + createRequest.Secret + "' >> /etc/rsyncd.secrets"); err != nil {
if out, err := shell.Execf("echo '" + createRequest.AuthUser + ":" + createRequest.Secret + "' >> /etc/rsyncd.secrets"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -172,7 +173,7 @@ func (r *RsyncController) Destroy(ctx http.Context) http.Response {
match := regexp.MustCompile(`auth users = ([^\n]+)`).FindStringSubmatch(module)
if len(match) == 2 {
authUser := match[1]
if out, err := tools.Exec("sed -i '/^" + authUser + ":.*$/d' /etc/rsyncd.secrets"); err != nil {
if out, err := shell.Execf("sed -i '/^" + authUser + ":.*$/d' /etc/rsyncd.secrets"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
}
@@ -230,7 +231,7 @@ secrets file = /etc/rsyncd.secrets
match := regexp.MustCompile(`auth users = ([^\n]+)`).FindStringSubmatch(module)
if len(match) == 2 {
authUser := match[1]
if out, err := tools.Exec("sed -i '/^" + authUser + ":.*$/d' /etc/rsyncd.secrets"); err != nil {
if out, err := shell.Execf("sed -i '/^" + authUser + ":.*$/d' /etc/rsyncd.secrets"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
}
@@ -238,7 +239,7 @@ secrets file = /etc/rsyncd.secrets
if err = tools.Write("/etc/rsyncd.conf", config, 0644); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
}
if out, err := tools.Exec("echo '" + updateRequest.AuthUser + ":" + updateRequest.Secret + "' >> /etc/rsyncd.secrets"); err != nil {
if out, err := shell.Execf("echo '" + updateRequest.AuthUser + ":" + updateRequest.Secret + "' >> /etc/rsyncd.secrets"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/TheTNB/panel/app/http/controllers"
"github.com/TheTNB/panel/internal"
"github.com/TheTNB/panel/internal/services"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -90,16 +91,16 @@ func (r *S3fsController) Add(ctx http.Context) http.Response {
if err := tools.Write("/etc/passwd-s3fs-"+cast.ToString(id), password, 0600); err != nil {
return nil
}
out, err := tools.Exec(`echo 's3fs#` + bucket + ` ` + path + ` fuse _netdev,allow_other,nonempty,url=` + url + `,passwd_file=/etc/passwd-s3fs-` + cast.ToString(id) + ` 0 0' >> /etc/fstab`)
out, err := shell.Execf(`echo 's3fs#` + bucket + ` ` + path + ` fuse _netdev,allow_other,nonempty,url=` + url + `,passwd_file=/etc/passwd-s3fs-` + cast.ToString(id) + ` 0 0' >> /etc/fstab`)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if mountCheck, err := tools.Exec("mount -a 2>&1"); err != nil {
_, _ = tools.Exec(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`)
if mountCheck, err := shell.Execf("mount -a 2>&1"); err != nil {
_, _ = shell.Execf(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`)
return controllers.Error(ctx, http.StatusInternalServerError, "检测到/etc/fstab有误: "+mountCheck)
}
if _, err := tools.Exec("df -h | grep " + path + " 2>&1"); err != nil {
_, _ = tools.Exec(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`)
if _, err := shell.Execf("df -h | grep " + path + " 2>&1"); err != nil {
_, _ = shell.Execf(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`)
return controllers.Error(ctx, http.StatusInternalServerError, "挂载失败,请检查配置是否正确")
}
@@ -145,16 +146,16 @@ func (r *S3fsController) Delete(ctx http.Context) http.Response {
return controllers.Error(ctx, http.StatusUnprocessableEntity, "挂载ID不存在")
}
if out, err := tools.Exec(`fusermount -u '` + mount.Path + `' 2>&1`); err != nil {
if out, err := shell.Execf(`fusermount -u '` + mount.Path + `' 2>&1`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec(`umount '` + mount.Path + `' 2>&1`); err != nil {
if out, err := shell.Execf(`umount '` + mount.Path + `' 2>&1`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec(`sed -i 's@^s3fs#` + mount.Bucket + `\s` + mount.Path + `.*$@@g' /etc/fstab`); err != nil {
if out, err := shell.Execf(`sed -i 's@^s3fs#` + mount.Bucket + `\s` + mount.Path + `.*$@@g' /etc/fstab`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
if mountCheck, err := tools.Exec("mount -a 2>&1"); err != nil {
if mountCheck, err := shell.Execf("mount -a 2>&1"); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "检测到/etc/fstab有误: "+mountCheck)
}
if err := tools.Remove("/etc/passwd-s3fs-" + cast.ToString(mount.ID)); err != nil {

View File

@@ -5,10 +5,11 @@ import (
"strconv"
"strings"
"github.com/TheTNB/panel/pkg/tools"
"github.com/goravel/framework/contracts/http"
"github.com/TheTNB/panel/app/http/controllers"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
)
type SupervisorController struct {
@@ -35,7 +36,7 @@ func (r *SupervisorController) Service(ctx http.Context) http.Response {
// Log 日志
func (r *SupervisorController) Log(ctx http.Context) http.Response {
log, err := tools.Exec(`tail -n 200 /var/log/supervisor/supervisord.log`)
log, err := shell.Execf(`tail -n 200 /var/log/supervisor/supervisord.log`)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, log)
}
@@ -45,7 +46,7 @@ func (r *SupervisorController) Log(ctx http.Context) http.Response {
// ClearLog 清空日志
func (r *SupervisorController) ClearLog(ctx http.Context) http.Response {
if out, err := tools.Exec(`echo "" > /var/log/supervisor/supervisord.log`); err != nil {
if out, err := shell.Execf(`echo "" > /var/log/supervisor/supervisord.log`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -99,7 +100,7 @@ func (r *SupervisorController) Processes(ctx http.Context) http.Response {
Uptime string `json:"uptime"`
}
out, err := tools.Exec(`supervisorctl status | awk '{print $1}'`)
out, err := shell.Execf(`supervisorctl status | awk '{print $1}'`)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -112,13 +113,13 @@ func (r *SupervisorController) Processes(ctx http.Context) http.Response {
var p process
p.Name = line
if status, err := tools.Exec(`supervisorctl status ` + line + ` | awk '{print $2}'`); err == nil {
if status, err := shell.Execf(`supervisorctl status ` + line + ` | awk '{print $2}'`); err == nil {
p.Status = status
}
if p.Status == "RUNNING" {
pid, _ := tools.Exec(`supervisorctl status ` + line + ` | awk '{print $4}'`)
pid, _ := shell.Execf(`supervisorctl status ` + line + ` | awk '{print $4}'`)
p.Pid = strings.ReplaceAll(pid, ",", "")
uptime, _ := tools.Exec(`supervisorctl status ` + line + ` | awk '{print $6}'`)
uptime, _ := shell.Execf(`supervisorctl status ` + line + ` | awk '{print $6}'`)
p.Uptime = uptime
} else {
p.Pid = "-"
@@ -138,7 +139,7 @@ func (r *SupervisorController) Processes(ctx http.Context) http.Response {
// StartProcess 启动进程
func (r *SupervisorController) StartProcess(ctx http.Context) http.Response {
process := ctx.Request().Input("process")
if out, err := tools.Exec(`supervisorctl start ` + process); err != nil {
if out, err := shell.Execf(`supervisorctl start %s`, process); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -148,7 +149,7 @@ func (r *SupervisorController) StartProcess(ctx http.Context) http.Response {
// StopProcess 停止进程
func (r *SupervisorController) StopProcess(ctx http.Context) http.Response {
process := ctx.Request().Input("process")
if out, err := tools.Exec(`supervisorctl stop ` + process); err != nil {
if out, err := shell.Execf(`supervisorctl stop %s`, process); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -158,7 +159,7 @@ func (r *SupervisorController) StopProcess(ctx http.Context) http.Response {
// RestartProcess 重启进程
func (r *SupervisorController) RestartProcess(ctx http.Context) http.Response {
process := ctx.Request().Input("process")
if out, err := tools.Exec(`supervisorctl restart ` + process); err != nil {
if out, err := shell.Execf(`supervisorctl restart %s`, process); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -171,16 +172,16 @@ func (r *SupervisorController) ProcessLog(ctx http.Context) http.Response {
var logPath string
var err error
if tools.IsRHEL() {
logPath, err = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
logPath, err = shell.Execf(`cat '/etc/supervisord.d/%s.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`, process)
} else {
logPath, err = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
logPath, err = shell.Execf(`cat '/etc/supervisor/conf.d/%s.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`, process)
}
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "无法从进程"+process+"的配置文件中获取日志路径")
}
log, err := tools.Exec(`tail -n 200 ` + logPath)
log, err := shell.Execf(`tail -n 200 ` + logPath)
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, log)
}
@@ -194,16 +195,16 @@ func (r *SupervisorController) ClearProcessLog(ctx http.Context) http.Response {
var logPath string
var err error
if tools.IsRHEL() {
logPath, err = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
logPath, err = shell.Execf(`cat '/etc/supervisord.d/%s.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`, process)
} else {
logPath, err = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
logPath, err = shell.Execf(`cat '/etc/supervisor/conf.d/%s.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`, process)
}
if err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, "无法从进程"+process+"的配置文件中获取日志路径")
return controllers.Error(ctx, http.StatusInternalServerError, fmt.Sprintf("无法从进程%s的配置文件中获取日志路径", process))
}
if out, err := tools.Exec(`echo "" > ` + logPath); err != nil {
if out, err := shell.Execf(`echo "" > ` + logPath); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
@@ -243,9 +244,9 @@ func (r *SupervisorController) SaveProcessConfig(ctx http.Context) http.Response
return controllers.Error(ctx, http.StatusUnprocessableEntity, err.Error())
}
_, _ = tools.Exec(`supervisorctl reread`)
_, _ = tools.Exec(`supervisorctl update`)
_, _ = tools.Exec(`supervisorctl restart ` + process)
_, _ = shell.Execf(`supervisorctl reread`)
_, _ = shell.Execf(`supervisorctl update`)
_, _ = shell.Execf(`supervisorctl restart %s`, process)
return controllers.Success(ctx, nil)
}
@@ -291,9 +292,9 @@ stdout_logfile_maxbytes=2MB
return controllers.Error(ctx, http.StatusUnprocessableEntity, err.Error())
}
_, _ = tools.Exec(`supervisorctl reread`)
_, _ = tools.Exec(`supervisorctl update`)
_, _ = tools.Exec(`supervisorctl start ` + name)
_, _ = shell.Execf(`supervisorctl reread`)
_, _ = shell.Execf(`supervisorctl update`)
_, _ = shell.Execf(`supervisorctl start %s`, name)
return controllers.Success(ctx, nil)
}
@@ -301,19 +302,19 @@ stdout_logfile_maxbytes=2MB
// DeleteProcess 删除进程
func (r *SupervisorController) DeleteProcess(ctx http.Context) http.Response {
process := ctx.Request().Input("process")
if out, err := tools.Exec(`supervisorctl stop ` + process); err != nil {
if out, err := shell.Execf(`supervisorctl stop %s`, process); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, out)
}
var logPath string
var err error
if tools.IsRHEL() {
logPath, err = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
logPath, err = shell.Execf(`cat '/etc/supervisord.d/%s.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`, process)
if err := tools.Remove(`/etc/supervisord.d/` + process + `.conf`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
}
} else {
logPath, err = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
logPath, err = shell.Execf(`cat '/etc/supervisor/conf.d/%s.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`, process)
if err := tools.Remove(`/etc/supervisor/conf.d/` + process + `.conf`); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
}
@@ -326,8 +327,8 @@ func (r *SupervisorController) DeleteProcess(ctx http.Context) http.Response {
if err := tools.Remove(logPath); err != nil {
return controllers.Error(ctx, http.StatusInternalServerError, err.Error())
}
_, _ = tools.Exec(`supervisorctl reread`)
_, _ = tools.Exec(`supervisorctl update`)
_, _ = shell.Execf(`supervisorctl reread`)
_, _ = shell.Execf(`supervisorctl update`)
return controllers.Success(ctx, nil)
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/spf13/cast"
"github.com/TheTNB/panel/app/http/controllers"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
)
@@ -74,7 +75,7 @@ func (r *ToolBoxController) GetSWAP(ctx http.Context) http.Response {
total = "0.00 B"
}
raw, err := tools.Exec("free | grep Swap")
raw, err := shell.Execf("free | grep Swap")
if err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取 SWAP 信息失败")
}
@@ -98,19 +99,19 @@ func (r *ToolBoxController) SetSWAP(ctx http.Context) http.Response {
size := ctx.Request().InputInt("size")
if tools.Exists("/www/swap") {
if out, err := tools.Exec("swapoff /www/swap"); err != nil {
if out, err := shell.Execf("swapoff /www/swap"); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, out)
}
if out, err := tools.Exec("rm -f /www/swap"); err != nil {
if out, err := shell.Execf("rm -f /www/swap"); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, out)
}
if out, err := tools.Exec("sed -i '/www\\/swap/d' /etc/fstab"); err != nil {
if out, err := shell.Execf("sed -i '/www\\/swap/d' /etc/fstab"); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, out)
}
}
if size > 1 {
free, err := tools.Exec("df -k /www | awk '{print $4}' | tail -n 1")
free, err := shell.Execf("df -k /www | awk '{print $4}' | tail -n 1")
if err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取磁盘空间失败")
}
@@ -118,26 +119,26 @@ func (r *ToolBoxController) SetSWAP(ctx http.Context) http.Response {
return controllers.Error(ctx, http.StatusUnprocessableEntity, "磁盘空间不足,当前剩余 "+tools.FormatBytes(cast.ToFloat64(free)))
}
btrfsCheck, _ := tools.Exec("df -T /www | awk '{print $2}' | tail -n 1")
btrfsCheck, _ := shell.Execf("df -T /www | awk '{print $2}' | tail -n 1")
if strings.Contains(btrfsCheck, "btrfs") {
if out, err := tools.Exec("btrfs filesystem mkswapfile --size " + cast.ToString(size) + "M --uuid clear /www/swap"); err != nil {
if out, err := shell.Execf("btrfs filesystem mkswapfile --size " + cast.ToString(size) + "M --uuid clear /www/swap"); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, out)
}
} else {
if out, err := tools.Exec("dd if=/dev/zero of=/www/swap bs=1M count=" + cast.ToString(size)); err != nil {
if out, err := shell.Execf("dd if=/dev/zero of=/www/swap bs=1M count=" + cast.ToString(size)); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, out)
}
if out, err := tools.Exec("mkswap -f /www/swap"); err != nil {
if out, err := shell.Execf("mkswap -f /www/swap"); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, out)
}
if err := tools.Chmod("/www/swap", 0600); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, "设置 SWAP 权限失败")
}
}
if out, err := tools.Exec("swapon /www/swap"); err != nil {
if out, err := shell.Execf("swapon /www/swap"); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, out)
}
if out, err := tools.Exec("echo '/www/swap swap swap defaults 0 0' >> /etc/fstab"); err != nil {
if out, err := shell.Execf("echo '/www/swap swap swap defaults 0 0' >> /etc/fstab"); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, out)
}
}
@@ -147,7 +148,7 @@ func (r *ToolBoxController) SetSWAP(ctx http.Context) http.Response {
// GetTimezone 获取时区
func (r *ToolBoxController) GetTimezone(ctx http.Context) http.Response {
raw, err := tools.Exec("timedatectl | grep zone")
raw, err := shell.Execf("timedatectl | grep zone")
if err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取时区信息失败")
}
@@ -162,7 +163,7 @@ func (r *ToolBoxController) GetTimezone(ctx http.Context) http.Response {
Value string `json:"value"`
}
zonesRaw, err := tools.Exec("timedatectl list-timezones")
zonesRaw, err := shell.Execf("timedatectl list-timezones")
if err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取时区列表失败")
}
@@ -189,7 +190,7 @@ func (r *ToolBoxController) SetTimezone(ctx http.Context) http.Response {
return controllers.Error(ctx, http.StatusUnprocessableEntity, "时区不能为空")
}
if out, err := tools.Exec("timedatectl set-timezone " + timezone); err != nil {
if out, err := shell.Execf("timedatectl set-timezone %s", timezone); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, out)
}
@@ -231,7 +232,7 @@ func (r *ToolBoxController) SetRootPassword(ctx http.Context) http.Response {
}
password = strings.ReplaceAll(password, `'`, `\'`)
if out, err := tools.Exec(`yes '` + password + `' | passwd root`); err != nil {
if out, err := shell.Execf(`yes '` + password + `' | passwd root`); err != nil {
return controllers.Error(ctx, http.StatusUnprocessableEntity, out)
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/goravel/framework/contracts/http"
"github.com/spf13/cast"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
)
@@ -42,7 +43,7 @@ func (r *SafeController) SetFirewallStatus(ctx http.Context) http.Response {
err = tools.ServiceEnable("firewalld")
}
} else {
_, err = tools.Exec("echo y | ufw enable")
_, err = shell.Execf("echo y | ufw enable")
if err == nil {
err = tools.ServiceStart("ufw")
}
@@ -57,7 +58,7 @@ func (r *SafeController) SetFirewallStatus(ctx http.Context) http.Response {
err = tools.ServiceDisable("firewalld")
}
} else {
_, err = tools.Exec("ufw disable")
_, err = shell.Execf("ufw disable")
if err == nil {
err = tools.ServiceStop("ufw")
}
@@ -82,7 +83,7 @@ func (r *SafeController) GetFirewallRules(ctx http.Context) http.Response {
var rules []map[string]string
if tools.IsRHEL() {
out, err := tools.Exec("firewall-cmd --list-all 2>&1")
out, err := shell.Execf("firewall-cmd --list-all")
if err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
@@ -103,7 +104,7 @@ func (r *SafeController) GetFirewallRules(ctx http.Context) http.Response {
})
}
} else {
out, err := tools.Exec("ufw status | grep -v '(v6)' | grep ALLOW | awk '{print $1}'")
out, err := shell.Execf("ufw status | grep -v '(v6)' | grep ALLOW | awk '{print $1}'")
if err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
@@ -158,13 +159,13 @@ func (r *SafeController) AddFirewallRule(ctx http.Context) http.Response {
}
if tools.IsRHEL() {
if out, err := tools.Exec("firewall-cmd --remove-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1"); err != nil {
if out, err := shell.Execf("firewall-cmd --remove-port=%s/%s --permanent", port, protocol); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("firewall-cmd --add-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1"); err != nil {
if out, err := shell.Execf("firewall-cmd --add-port=%s/%s --permanent", port, protocol); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("firewall-cmd --reload"); err != nil {
if out, err := shell.Execf("firewall-cmd --reload"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
} else {
@@ -172,13 +173,13 @@ func (r *SafeController) AddFirewallRule(ctx http.Context) http.Response {
if strings.Contains(port, "-") {
port = strings.ReplaceAll(port, "-", ":")
}
if out, err := tools.Exec("ufw delete allow " + cast.ToString(port) + "/" + protocol); err != nil {
if out, err := shell.Execf("ufw delete allow %s/%s", port, protocol); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("ufw allow " + cast.ToString(port) + "/" + protocol); err != nil {
if out, err := shell.Execf("ufw allow %s/%s", port, protocol); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("ufw reload"); err != nil {
if out, err := shell.Execf("ufw reload"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
}
@@ -192,24 +193,24 @@ func (r *SafeController) DeleteFirewallRule(ctx http.Context) http.Response {
return Error(ctx, http.StatusUnprocessableEntity, "防火墙未启动")
}
port := ctx.Request().InputInt("port", 0)
protocol := ctx.Request().Input("protocol", "")
if port == 0 || protocol == "" {
port := ctx.Request().Input("port")
protocol := ctx.Request().Input("protocol")
if port == "" || protocol == "" {
return Error(ctx, http.StatusUnprocessableEntity, "参数错误")
}
if tools.IsRHEL() {
if out, err := tools.Exec("firewall-cmd --remove-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1"); err != nil {
if out, err := shell.Execf("firewall-cmd --remove-port=%s/%s --permanent", port, protocol); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("firewall-cmd --reload"); err != nil {
if out, err := shell.Execf("firewall-cmd --reload"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
} else {
if out, err := tools.Exec("ufw delete allow " + cast.ToString(port) + "/" + protocol); err != nil {
if out, err := shell.Execf("ufw delete allow %s/%s", port, protocol); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("ufw reload"); err != nil {
if out, err := shell.Execf("ufw reload"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
}
@@ -262,7 +263,7 @@ func (r *SafeController) SetSshStatus(ctx http.Context) http.Response {
// GetSshPort 获取 SSH 端口
func (r *SafeController) GetSshPort(ctx http.Context) http.Response {
out, err := tools.Exec("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
out, err := shell.Execf("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
if err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
@@ -277,12 +278,12 @@ func (r *SafeController) SetSshPort(ctx http.Context) http.Response {
return Error(ctx, http.StatusUnprocessableEntity, "参数错误")
}
oldPort, err := tools.Exec("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
oldPort, err := shell.Execf("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
if err != nil {
return Error(ctx, http.StatusInternalServerError, oldPort)
}
_, _ = tools.Exec("sed -i 's/#Port " + oldPort + "/Port " + cast.ToString(port) + "/g' /etc/ssh/sshd_config")
_, _ = tools.Exec("sed -i 's/Port " + oldPort + "/Port " + cast.ToString(port) + "/g' /etc/ssh/sshd_config")
_, _ = shell.Execf("sed -i 's/#Port %s/Port %d/g' /etc/ssh/sshd_config", oldPort, port)
_, _ = shell.Execf("sed -i 's/Port %s/Port %d/g' /etc/ssh/sshd_config", oldPort, port)
status, _ := tools.ServiceStatus(r.ssh)
if status {
@@ -295,7 +296,7 @@ func (r *SafeController) SetSshPort(ctx http.Context) http.Response {
// GetPingStatus 获取 Ping 状态
func (r *SafeController) GetPingStatus(ctx http.Context) http.Response {
if tools.IsRHEL() {
out, err := tools.Exec(`firewall-cmd --list-all 2>&1`)
out, err := shell.Execf(`firewall-cmd --list-all`)
if err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
@@ -324,15 +325,15 @@ func (r *SafeController) SetPingStatus(ctx http.Context) http.Response {
var err error
if tools.IsRHEL() {
if ctx.Request().InputBool("status") {
out, err = tools.Exec(`firewall-cmd --permanent --remove-rich-rule='rule protocol value=icmp drop'`)
out, err = shell.Execf(`firewall-cmd --permanent --remove-rich-rule='rule protocol value=icmp drop'`)
} else {
out, err = tools.Exec(`firewall-cmd --permanent --add-rich-rule='rule protocol value=icmp drop'`)
out, err = shell.Execf(`firewall-cmd --permanent --add-rich-rule='rule protocol value=icmp drop'`)
}
} else {
if ctx.Request().InputBool("status") {
out, err = tools.Exec(`sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j DROP/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/g' /etc/ufw/before.rules`)
out, err = shell.Execf(`sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j DROP/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/g' /etc/ufw/before.rules`)
} else {
out, err = tools.Exec(`sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/-A ufw-before-input -p icmp --icmp-type echo-request -j DROP/g' /etc/ufw/before.rules`)
out, err = shell.Execf(`sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/-A ufw-before-input -p icmp --icmp-type echo-request -j DROP/g' /etc/ufw/before.rules`)
}
}
@@ -341,9 +342,9 @@ func (r *SafeController) SetPingStatus(ctx http.Context) http.Response {
}
if tools.IsRHEL() {
out, err = tools.Exec(`firewall-cmd --reload`)
out, err = shell.Execf(`firewall-cmd --reload`)
} else {
out, err = tools.Exec(`ufw reload`)
out, err = shell.Execf(`ufw reload`)
}
if err != nil {

View File

@@ -9,6 +9,7 @@ import (
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/internal"
"github.com/TheTNB/panel/internal/services"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
)
@@ -50,7 +51,7 @@ func (r *SettingController) List(ctx http.Context) http.Response {
return ErrorSystem(ctx)
}
port, err := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
port, err := shell.Execf(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
if err != nil {
facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{
"error": err.Error(),
@@ -147,7 +148,7 @@ func (r *SettingController) Update(ctx http.Context) http.Response {
return ErrorSystem(ctx)
}
oldPort, err := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
oldPort, err := shell.Execf(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
if err != nil {
facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{
"error": err.Error(),
@@ -157,33 +158,33 @@ func (r *SettingController) Update(ctx http.Context) http.Response {
port := cast.ToString(updateRequest.Port)
if oldPort != port {
if out, err := tools.Exec("sed -i 's/APP_PORT=" + oldPort + "/APP_PORT=" + port + "/g' /www/panel/panel.conf"); err != nil {
if out, err := shell.Execf("sed -i 's/APP_PORT=%s/APP_PORT=%s/g' /www/panel/panel.conf", oldPort, port); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if tools.IsRHEL() {
if out, err := tools.Exec("firewall-cmd --remove-port=" + cast.ToString(port) + "/tcp --permanent 2>&1"); err != nil {
if out, err := shell.Execf("firewall-cmd --remove-port=%s/tcp --permanent", oldPort); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("firewall-cmd --add-port=" + cast.ToString(port) + "/tcp --permanent 2>&1"); err != nil {
if out, err := shell.Execf("firewall-cmd --add-port=%s/tcp --permanent", port); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("firewall-cmd --reload"); err != nil {
if out, err := shell.Execf("firewall-cmd --reload"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
} else {
if out, err := tools.Exec("ufw delete allow " + cast.ToString(port) + "/tcp"); err != nil {
if out, err := shell.Execf("ufw delete allow %s/tcp", oldPort); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("ufw allow " + cast.ToString(port) + "/tcp"); err != nil {
if out, err := shell.Execf("ufw allow %s/tcp", port); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
if out, err := tools.Exec("ufw reload"); err != nil {
if out, err := shell.Execf("ufw reload"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
}
}
oldEntrance, err := tools.Exec(`cat /www/panel/panel.conf | grep APP_ENTRANCE | awk -F '=' '{print $2}' | tr -d '\n'`)
oldEntrance, err := shell.Execf(`cat /www/panel/panel.conf | grep APP_ENTRANCE | awk -F '=' '{print $2}' | tr -d '\n'`)
if err != nil {
facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{
"error": err.Error(),
@@ -192,12 +193,12 @@ func (r *SettingController) Update(ctx http.Context) http.Response {
}
entrance := cast.ToString(updateRequest.Entrance)
if oldEntrance != entrance {
if out, err := tools.Exec("sed -i 's!APP_ENTRANCE=" + oldEntrance + "!APP_ENTRANCE=" + entrance + "!g' /www/panel/panel.conf"); err != nil {
if out, err := shell.Execf("sed -i 's!APP_ENTRANCE=" + oldEntrance + "!APP_ENTRANCE=" + entrance + "!g' /www/panel/panel.conf"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
}
oldLanguage, err := tools.Exec(`cat /www/panel/panel.conf | grep APP_LOCALE | awk -F '=' '{print $2}' | tr -d '\n'`)
oldLanguage, err := shell.Execf(`cat /www/panel/panel.conf | grep APP_LOCALE | awk -F '=' '{print $2}' | tr -d '\n'`)
if err != nil {
facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{
"error": err.Error(),
@@ -205,17 +206,17 @@ func (r *SettingController) Update(ctx http.Context) http.Response {
return ErrorSystem(ctx)
}
if oldLanguage != updateRequest.Language {
if out, err := tools.Exec("sed -i 's/APP_LOCALE=" + oldLanguage + "/APP_LOCALE=" + updateRequest.Language + "/g' /www/panel/panel.conf"); err != nil {
if out, err := shell.Execf("sed -i 's/APP_LOCALE=" + oldLanguage + "/APP_LOCALE=" + updateRequest.Language + "/g' /www/panel/panel.conf"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
}
if updateRequest.SSL {
if out, err := tools.Exec("sed -i 's/APP_SSL=false/APP_SSL=true/g' /www/panel/panel.conf"); err != nil {
if out, err := shell.Execf("sed -i 's/APP_SSL=false/APP_SSL=true/g' /www/panel/panel.conf"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
} else {
if out, err := tools.Exec("sed -i 's/APP_SSL=true/APP_SSL=false/g' /www/panel/panel.conf"); err != nil {
if out, err := shell.Execf("sed -i 's/APP_SSL=true/APP_SSL=false/g' /www/panel/panel.conf"); err != nil {
return Error(ctx, http.StatusInternalServerError, out)
}
}

View File

@@ -5,7 +5,7 @@ import (
"github.com/goravel/framework/facades"
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/pkg/shell"
)
type TaskController struct {
@@ -63,7 +63,7 @@ func (r *TaskController) Log(ctx http.Context) http.Response {
return ErrorSystem(ctx)
}
log, err := tools.Exec(`tail -n 500 '` + task.Log + `'`)
log, err := shell.Execf(`tail -n 500 '` + task.Log + `'`)
if err != nil {
return Error(ctx, http.StatusInternalServerError, "日志已被清理")
}

View File

@@ -1,10 +1,10 @@
package jobs
import (
"github.com/TheTNB/panel/pkg/tools"
"github.com/goravel/framework/facades"
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/pkg/shell"
)
// ProcessTask 处理面板任务
@@ -48,7 +48,7 @@ func (receiver *ProcessTask) Handle(args ...any) error {
"task_id": taskID,
}).Infof("开始执行任务")
if _, err := tools.Exec(task.Shell); err != nil {
if _, err := shell.Execf(task.Shell); err != nil {
task.Status = models.TaskStatusFailed
if err := facades.Orm().Query().Save(&task); err != nil {
facades.Log().Tags("面板", "异步任务").With(map[string]any{

View File

@@ -11,6 +11,7 @@ import (
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/internal"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -73,7 +74,7 @@ func (s *BackupImpl) WebSiteBackup(website models.Website) error {
}
backupFile := backupPath + "/" + website.Name + "_" + carbon.Now().ToShortDateTimeString() + ".zip"
if _, err := tools.Exec(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`); err != nil {
if _, err := shell.Execf(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`); err != nil {
return err
}
@@ -163,10 +164,10 @@ func (s *BackupImpl) MysqlBackup(database string) error {
return err
}
if _, err := tools.Exec("/www/server/mysql/bin/mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile); err != nil {
if _, err := shell.Execf("/www/server/mysql/bin/mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile); err != nil {
return err
}
if _, err := tools.Exec("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile); err != nil {
if _, err := shell.Execf("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile); err != nil {
return err
}
if err := tools.Remove(backupPath + "/" + backupFile); err != nil {
@@ -217,7 +218,7 @@ func (s *BackupImpl) MysqlRestore(database string, backupFile string) error {
return errors.New("无法找到备份文件")
}
if _, err = tools.Exec("/www/server/mysql/bin/mysql -uroot " + database + " < " + filepath.Join(tempDir, backupFile)); err != nil {
if _, err = shell.Execf("/www/server/mysql/bin/mysql -uroot " + database + " < " + filepath.Join(tempDir, backupFile)); err != nil {
return err
}
@@ -271,10 +272,10 @@ func (s *BackupImpl) PostgresqlBackup(database string) error {
}
}
if _, err := tools.Exec(`su - postgres -c "pg_dump ` + database + `" > ` + backupPath + "/" + backupFile); err != nil {
if _, err := shell.Execf(`su - postgres -c "pg_dump ` + database + `" > ` + backupPath + "/" + backupFile); err != nil {
return err
}
if _, err := tools.Exec("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile); err != nil {
if _, err := shell.Execf("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile); err != nil {
return err
}
@@ -317,7 +318,7 @@ func (s *BackupImpl) PostgresqlRestore(database string, backupFile string) error
return errors.New("无法找到备份文件")
}
if _, err = tools.Exec(`su - postgres -c "psql ` + database + `" < ` + filepath.Join(tempDir, backupFile)); err != nil {
if _, err = shell.Execf(`su - postgres -c "psql ` + database + `" < ` + filepath.Join(tempDir, backupFile)); err != nil {
return err
}

View File

@@ -6,6 +6,7 @@ import (
"strings"
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
)
@@ -19,14 +20,14 @@ func NewCronImpl() *CronImpl {
// AddToSystem 添加到系统
func (r *CronImpl) AddToSystem(cron models.Cron) error {
if tools.IsRHEL() {
if _, err := tools.Exec(fmt.Sprintf(`echo "%s %s >> %s 2>&1" >> /var/spool/cron/root`, cron.Time, cron.Shell, cron.Log)); err != nil {
if _, err := shell.Execf(fmt.Sprintf(`echo "%s %s >> %s 2>&1" >> /var/spool/cron/root`, cron.Time, cron.Shell, cron.Log)); err != nil {
return err
}
return tools.ServiceRestart("crond")
}
if tools.IsDebian() {
if _, err := tools.Exec(fmt.Sprintf(`echo "%s %s >> %s 2>&1" >> /var/spool/cron/crontabs/root`, cron.Time, cron.Shell, cron.Log)); err != nil {
if _, err := shell.Execf(fmt.Sprintf(`echo "%s %s >> %s 2>&1" >> /var/spool/cron/crontabs/root`, cron.Time, cron.Shell, cron.Log)); err != nil {
return err
}
return tools.ServiceRestart("cron")
@@ -40,14 +41,14 @@ func (r *CronImpl) DeleteFromSystem(cron models.Cron) error {
// 需要转义 shell 路径的/为\/
cron.Shell = strings.ReplaceAll(cron.Shell, "/", "\\/")
if tools.IsRHEL() {
if _, err := tools.Exec("sed -i '/" + cron.Shell + "/d' /var/spool/cron/root"); err != nil {
if _, err := shell.Execf("sed -i '/" + cron.Shell + "/d' /var/spool/cron/root"); err != nil {
return err
}
return tools.ServiceRestart("crond")
}
if tools.IsDebian() {
if _, err := tools.Exec("sed -i '/" + cron.Shell + "/d' /var/spool/cron/crontabs/root"); err != nil {
if _, err := shell.Execf("sed -i '/" + cron.Shell + "/d' /var/spool/cron/crontabs/root"); err != nil {
return err
}
return tools.ServiceRestart("cron")

View File

@@ -13,6 +13,7 @@ import (
"github.com/spf13/cast"
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -82,15 +83,15 @@ func (r *PHPImpl) Load() ([]types.NV, error) {
}
func (r *PHPImpl) GetErrorLog() (string, error) {
return tools.Exec("tail -n 500 /www/server/php/" + r.version + "/var/log/php-fpm.log")
return shell.Execf("tail -n 500 /www/server/php/%s/var/log/php-fpm.log", r.version)
}
func (r *PHPImpl) GetSlowLog() (string, error) {
return tools.Exec("tail -n 500 /www/server/php/" + r.version + "/var/log/slow.log")
return shell.Execf("tail -n 500 /www/server/php/%s/var/log/slow.log", r.version)
}
func (r *PHPImpl) ClearErrorLog() error {
if out, err := tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/php-fpm.log"); err != nil {
if out, err := shell.Execf("echo '' > /www/server/php/%s/var/log/php-fpm.log", r.version); err != nil {
return errors.New(out)
}
@@ -98,7 +99,7 @@ func (r *PHPImpl) ClearErrorLog() error {
}
func (r *PHPImpl) ClearSlowLog() error {
if out, err := tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/slow.log"); err != nil {
if out, err := shell.Execf("echo '' > /www/server/php/%s/var/log/slow.log", r.version); err != nil {
return errors.New(out)
}
@@ -270,7 +271,7 @@ func (r *PHPImpl) GetExtensions() ([]types.PHPExtension, error) {
})
}
raw, err := tools.Exec("/www/server/php/" + r.version + "/bin/php -m")
raw, err := shell.Execf("/www/server/php/%s/bin/php -m", r.version)
if err != nil {
return extensions, err
}

View File

@@ -16,6 +16,7 @@ import (
requests "github.com/TheTNB/panel/app/http/requests/website"
"github.com/TheTNB/panel/app/models"
"github.com/TheTNB/panel/internal"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/tools"
"github.com/TheTNB/panel/types"
)
@@ -285,18 +286,18 @@ server
rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword)
if website.Db && website.DbType == "mysql" {
_, _ = tools.Exec(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE DATABASE IF NOT EXISTS ` + website.DbName + ` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;"`)
_, _ = tools.Exec(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE USER '` + website.DbUser + `'@'localhost' IDENTIFIED BY '` + website.DbPassword + `';"`)
_, _ = tools.Exec(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "GRANT ALL PRIVILEGES ON ` + website.DbName + `.* TO '` + website.DbUser + `'@'localhost';"`)
_, _ = tools.Exec(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "FLUSH PRIVILEGES;"`)
_, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE DATABASE IF NOT EXISTS ` + website.DbName + ` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;"`)
_, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE USER '` + website.DbUser + `'@'localhost' IDENTIFIED BY '` + website.DbPassword + `';"`)
_, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "GRANT ALL PRIVILEGES ON ` + website.DbName + `.* TO '` + website.DbUser + `'@'localhost';"`)
_, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "FLUSH PRIVILEGES;"`)
}
if website.Db && website.DbType == "postgresql" {
_, _ = tools.Exec(`echo "CREATE DATABASE ` + website.DbName + `;" | su - postgres -c "psql"`)
_, _ = tools.Exec(`echo "CREATE USER ` + website.DbUser + ` WITH PASSWORD '` + website.DbPassword + `';" | su - postgres -c "psql"`)
_, _ = tools.Exec(`echo "ALTER DATABASE ` + website.DbName + ` OWNER TO ` + website.DbUser + `;" | su - postgres -c "psql"`)
_, _ = tools.Exec(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + website.DbName + ` TO ` + website.DbUser + `;" | su - postgres -c "psql"`)
_, _ = shell.Execf(`echo "CREATE DATABASE ` + website.DbName + `;" | su - postgres -c "psql"`)
_, _ = shell.Execf(`echo "CREATE USER ` + website.DbUser + ` WITH PASSWORD '` + website.DbPassword + `';" | su - postgres -c "psql"`)
_, _ = shell.Execf(`echo "ALTER DATABASE ` + website.DbName + ` OWNER TO ` + website.DbUser + `;" | su - postgres -c "psql"`)
_, _ = shell.Execf(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + website.DbName + ` TO ` + website.DbUser + `;" | su - postgres -c "psql"`)
userConfig := "host " + website.DbName + " " + website.DbUser + " 127.0.0.1/32 scram-sha-256"
_, _ = tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`)
_, _ = shell.Execf(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`)
_ = tools.ServiceReload("postgresql")
}
@@ -659,7 +660,7 @@ func (r *WebsiteImpl) GetConfig(id uint) (types.WebsiteSetting, error) {
rewrite, _ := tools.Read("/www/server/vhost/rewrite/" + website.Name + ".conf")
setting.Rewrite = rewrite
log, _ := tools.Exec(`tail -n 100 '/www/wwwlogs/` + website.Name + `.log'`)
log, _ := shell.Execf(`tail -n 100 '/www/wwwlogs/%s.log'`, website.Name)
setting.Log = log
return setting, err

119
pkg/shell/exec.go Normal file
View File

@@ -0,0 +1,119 @@
package shell
import (
"bytes"
"errors"
"fmt"
"os"
"os/exec"
"strings"
"time"
"github.com/TheTNB/panel/pkg/slice"
"github.com/goravel/framework/support"
)
// Execf 执行 shell 命令
func Execf(shell string, args ...any) (string, error) {
if !CheckArgs(slice.ToString(args)...) {
return "", errors.New("你想干什么?")
}
var cmd *exec.Cmd
_ = os.Setenv("LC_ALL", "C")
cmd = exec.Command("bash", "-c", fmt.Sprintf(shell, args...))
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
return "", errors.New(strings.TrimSpace(stderr.String()))
}
return strings.TrimSpace(stdout.String()), err
}
// ExecfAsync 异步执行 shell 命令
func ExecfAsync(shell string, args ...any) error {
if !CheckArgs(slice.ToString(args)...) {
return errors.New("你想干什么?")
}
var cmd *exec.Cmd
_ = os.Setenv("LC_ALL", "C")
cmd = exec.Command("bash", "-c", fmt.Sprintf(shell, args...))
err := cmd.Start()
if err != nil {
return err
}
go func() {
err := cmd.Wait()
if err != nil {
if support.Env == support.EnvTest {
fmt.Println(err.Error())
panic(err)
}
}
}()
return nil
}
// ExecfWithTimeout 执行 shell 命令并设置超时时间
func ExecfWithTimeout(timeout time.Duration, shell string, args ...any) (string, error) {
if !CheckArgs(slice.ToString(args)...) {
return "", errors.New("你想干什么?")
}
var cmd *exec.Cmd
_ = os.Setenv("LC_ALL", "C")
cmd = exec.Command("bash", "-c", fmt.Sprintf(shell, args...))
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Start()
if err != nil {
return "", err
}
done := make(chan error)
go func() {
done <- cmd.Wait()
}()
select {
case <-time.After(timeout):
_ = cmd.Process.Kill()
return "", errors.New("执行超时")
case err = <-done:
if err != nil {
return "", errors.New(strings.TrimSpace(stderr.String()))
}
}
return strings.TrimSpace(stdout.String()), err
}
// CheckArgs 检查危险的参数
func CheckArgs(args ...string) bool {
if len(args) == 0 {
return true
}
dangerous := []string{"&", "|", ";", "$", "'", `"`, "(", ")", "`", "\n", "\r", ">", "<", "{", "}", "[", "]", "\\"}
for _, arg := range args {
for _, char := range dangerous {
if strings.Contains(arg, char) {
return false
}
}
}
return true
}

30
pkg/slice/slice.go Normal file
View File

@@ -0,0 +1,30 @@
package slice
import "github.com/spf13/cast"
// ToAny 将任意类型切片转换为 []any
func ToAny[T any](s []T) []any {
result := make([]any, len(s))
for i, v := range s {
result[i] = v
}
return result
}
// ToString 将任意类型切片转换为 []string
func ToString[T any](s []T) []string {
result := make([]string, len(s))
for i, v := range s {
result[i] = cast.ToString(v)
}
return result
}
// ToInt 将任意类型切片转换为 []int
func ToInt[T any](s []T) []int {
result := make([]int, len(s))
for i, v := range s {
result[i] = cast.ToInt(v)
}
return result
}

View File

@@ -2,14 +2,15 @@ package tools
import (
"errors"
"fmt"
"os/exec"
"strings"
"github.com/TheTNB/panel/pkg/shell"
)
// ServiceStatus 获取服务状态
func ServiceStatus(name string) (bool, error) {
output, err := Exec(fmt.Sprintf("systemctl status %s | grep Active | grep -v grep | awk '{print $2}'", name))
output, err := shell.Execf("systemctl status %s | grep Active | grep -v grep | awk '{print $2}'", name)
return output == "active", err
}
@@ -37,36 +38,36 @@ func ServiceIsEnabled(name string) (bool, error) {
// ServiceStart 启动服务
func ServiceStart(name string) error {
_, err := Exec(fmt.Sprintf("systemctl start %s", name))
_, err := shell.Execf("systemctl start %s", name)
return err
}
// ServiceStop 停止服务
func ServiceStop(name string) error {
_, err := Exec(fmt.Sprintf("systemctl stop %s", name))
_, err := shell.Execf("systemctl stop %s", name)
return err
}
// ServiceRestart 重启服务
func ServiceRestart(name string) error {
_, err := Exec(fmt.Sprintf("systemctl restart %s", name))
_, err := shell.Execf("systemctl restart %s", name)
return err
}
// ServiceReload 重载服务
func ServiceReload(name string) error {
_, err := Exec(fmt.Sprintf("systemctl reload %s", name))
_, err := shell.Execf("systemctl reload %s", name)
return err
}
// ServiceEnable 启用服务
func ServiceEnable(name string) error {
_, err := Exec(fmt.Sprintf("systemctl enable %s", name))
_, err := shell.Execf("systemctl enable %s", name)
return err
}
// ServiceDisable 禁用服务
func ServiceDisable(name string) error {
_, err := Exec(fmt.Sprintf("systemctl disable %s", name))
_, err := shell.Execf("systemctl disable %s", name)
return err
}

View File

@@ -1,7 +1,6 @@
package tools
import (
"bytes"
"errors"
"fmt"
"io"
@@ -11,7 +10,6 @@ import (
"path/filepath"
"strings"
"github.com/goravel/framework/support"
"github.com/goravel/framework/support/env"
"github.com/mholt/archiver/v3"
"github.com/spf13/cast"
@@ -58,54 +56,6 @@ func Remove(path string) error {
return os.RemoveAll(path)
}
// Exec 执行 shell 命令
func Exec(shell string) (string, error) {
var cmd *exec.Cmd
if env.IsLinux() {
cmd = exec.Command("bash", "-c", "LC_ALL=C "+shell)
} else {
cmd = exec.Command("cmd", "/C", "chcp 65001 >nul && "+shell)
}
var stdoutBuf, stderrBuf bytes.Buffer
cmd.Stdout = &stdoutBuf
cmd.Stderr = &stderrBuf
err := cmd.Run()
if err != nil {
return "", errors.New(strings.TrimSpace(stderrBuf.String()))
}
return strings.TrimSpace(stdoutBuf.String()), err
}
// ExecAsync 异步执行 shell 命令
func ExecAsync(shell string) error {
var cmd *exec.Cmd
if env.IsLinux() {
cmd = exec.Command("bash", "-c", "LC_ALL=C "+shell)
} else {
cmd = exec.Command("cmd", "/C", "chcp 65001 >nul && "+shell)
}
err := cmd.Start()
if err != nil {
return err
}
go func() {
err := cmd.Wait()
if err != nil {
if support.Env == support.EnvTest {
fmt.Println(err.Error())
panic(err)
}
}
}()
return nil
}
// Mkdir 创建目录
func Mkdir(path string, permission os.FileMode) error {
return os.MkdirAll(path, permission)

View File

@@ -4,7 +4,6 @@ package tools
import (
"errors"
"fmt"
"github.com/spf13/cast"
"os"
"strings"
"time"
@@ -19,6 +18,9 @@ import (
"github.com/shirou/gopsutil/load"
"github.com/shirou/gopsutil/mem"
"github.com/shirou/gopsutil/net"
"github.com/spf13/cast"
"github.com/TheTNB/panel/pkg/shell"
)
// MonitoringInfo 监控信息
@@ -159,9 +161,9 @@ func GetLatestPanelVersion() (PanelInfo, error) {
isChina := IsChina()
if isChina {
output, err = Exec(`curl -sSL "https://git.haozi.net/api/v4/projects/opensource%2Fpanel/releases/permalink/latest"`)
output, err = shell.Execf(`curl -sSL "https://git.haozi.net/api/v4/projects/opensource%2Fpanel/releases/permalink/latest"`)
} else {
output, err = Exec(`curl -sSL "https://api.github.com/repos/TheTNB/panel/releases/latest"`)
output, err = shell.Execf(`curl -sSL "https://api.github.com/repos/TheTNB/panel/releases/latest"`)
}
if len(output) == 0 || err != nil {
@@ -185,70 +187,70 @@ func GetLatestPanelVersion() (PanelInfo, error) {
var name, version, body, date, downloadName, downloadUrl, checksums, checksumsUrl string
if isChina {
if name, err = Exec("jq -r '.name' " + fileName); err != nil {
if name, err = shell.Execf("jq -r '.name' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if version, err = Exec("jq -r '.tag_name' " + fileName); err != nil {
if version, err = shell.Execf("jq -r '.tag_name' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if body, err = Exec("jq -r '.description' " + fileName); err != nil {
if body, err = shell.Execf("jq -r '.description' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if date, err = Exec("jq -r '.created_at' " + fileName); err != nil {
if date, err = shell.Execf("jq -r '.created_at' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if checksums, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .name' " + fileName); err != nil {
if checksums, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .name' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if checksumsUrl, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .direct_asset_url' " + fileName); err != nil {
if checksumsUrl, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .direct_asset_url' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if env.IsArm() {
if downloadName, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .name' " + fileName); err != nil {
if downloadName, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .name' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if downloadUrl, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .direct_asset_url' " + fileName); err != nil {
if downloadUrl, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .direct_asset_url' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
} else {
if downloadName, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName); err != nil {
if downloadName, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if downloadUrl, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .direct_asset_url' " + fileName); err != nil {
if downloadUrl, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .direct_asset_url' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
}
} else {
if name, err = Exec("jq -r '.name' " + fileName); err != nil {
if name, err = shell.Execf("jq -r '.name' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if version, err = Exec("jq -r '.tag_name' " + fileName); err != nil {
if version, err = shell.Execf("jq -r '.tag_name' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if body, err = Exec("jq -r '.body' " + fileName); err != nil {
if body, err = shell.Execf("jq -r '.body' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if date, err = Exec("jq -r '.published_at' " + fileName); err != nil {
if date, err = shell.Execf("jq -r '.published_at' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if checksums, err = Exec("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .name' " + fileName); err != nil {
if checksums, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .name' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if checksumsUrl, err = Exec("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .browser_download_url' " + fileName); err != nil {
if checksumsUrl, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .browser_download_url' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if env.IsArm() {
if downloadName, err = Exec("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .name' " + fileName); err != nil {
if downloadName, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .name' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if downloadUrl, err = Exec("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .browser_download_url' " + fileName); err != nil {
if downloadUrl, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .browser_download_url' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
} else {
if downloadName, err = Exec("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName); err != nil {
if downloadName, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
if downloadUrl, err = Exec("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .browser_download_url' " + fileName); err != nil {
if downloadUrl, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .browser_download_url' " + fileName); err != nil {
return info, errors.New("获取最新版本失败")
}
}
@@ -278,9 +280,9 @@ func GetPanelVersion(version string) (PanelInfo, error) {
}
if isChina {
output, err = Exec(`curl -sSL "https://git.haozi.net/api/v4/projects/opensource%2Fpanel/releases/` + version + `"`)
output, err = shell.Execf(`curl -sSL "https://git.haozi.net/api/v4/projects/opensource%2Fpanel/releases/` + version + `"`)
} else {
output, err = Exec(`curl -sSL "https://api.github.com/repos/TheTNB/panel/releases/tags/` + version + `"`)
output, err = shell.Execf(`curl -sSL "https://api.github.com/repos/TheTNB/panel/releases/tags/` + version + `"`)
}
if len(output) == 0 || err != nil {
@@ -304,70 +306,70 @@ func GetPanelVersion(version string) (PanelInfo, error) {
var name, version2, body, date, downloadName, downloadUrl, checksums, checksumsUrl string
if isChina {
if name, err = Exec("jq -r '.name' " + fileName); err != nil {
if name, err = shell.Execf("jq -r '.name' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if version2, err = Exec("jq -r '.tag_name' " + fileName); err != nil {
if version2, err = shell.Execf("jq -r '.tag_name' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if body, err = Exec("jq -r '.description' " + fileName); err != nil {
if body, err = shell.Execf("jq -r '.description' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if date, err = Exec("jq -r '.created_at' " + fileName); err != nil {
if date, err = shell.Execf("jq -r '.created_at' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if checksums, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .name' " + fileName); err != nil {
if checksums, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .name' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if checksumsUrl, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .direct_asset_url' " + fileName); err != nil {
if checksumsUrl, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .direct_asset_url' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if env.IsArm() {
if downloadName, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .name' " + fileName); err != nil {
if downloadName, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .name' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if downloadUrl, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .direct_asset_url' " + fileName); err != nil {
if downloadUrl, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .direct_asset_url' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
} else {
if downloadName, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName); err != nil {
if downloadName, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if downloadUrl, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .direct_asset_url' " + fileName); err != nil {
if downloadUrl, err = shell.Execf("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .direct_asset_url' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
}
} else {
if name, err = Exec("jq -r '.name' " + fileName); err != nil {
if name, err = shell.Execf("jq -r '.name' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if version2, err = Exec("jq -r '.tag_name' " + fileName); err != nil {
if version2, err = shell.Execf("jq -r '.tag_name' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if body, err = Exec("jq -r '.body' " + fileName); err != nil {
if body, err = shell.Execf("jq -r '.body' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if date, err = Exec("jq -r '.published_at' " + fileName); err != nil {
if date, err = shell.Execf("jq -r '.published_at' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if checksums, err = Exec("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .name' " + fileName); err != nil {
if checksums, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .name' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if checksumsUrl, err = Exec("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .browser_download_url' " + fileName); err != nil {
if checksumsUrl, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .browser_download_url' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if env.IsArm() {
if downloadName, err = Exec("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .name' " + fileName); err != nil {
if downloadName, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .name' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if downloadUrl, err = Exec("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .browser_download_url' " + fileName); err != nil {
if downloadUrl, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .browser_download_url' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
} else {
if downloadName, err = Exec("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName); err != nil {
if downloadName, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
if downloadUrl, err = Exec("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .browser_download_url' " + fileName); err != nil {
if downloadUrl, err = shell.Execf("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .browser_download_url' " + fileName); err != nil {
return info, errors.New("获取面板版本失败")
}
}
@@ -401,11 +403,11 @@ func UpdatePanel(panelInfo PanelInfo) error {
color.Red().Printfln("备份面板失败")
return err
}
if _, err := Exec("cd /www/panel/storage && zip -r /tmp/panel-storage.zip *"); err != nil {
if _, err := shell.Execf("cd /www/panel/storage && zip -r /tmp/panel-storage.zip *"); err != nil {
color.Red().Printfln("备份面板数据失败")
return err
}
if _, err := Exec("cp -f /www/panel/panel.conf /tmp/panel.conf.bak"); err != nil {
if _, err := shell.Execf("cp -f /www/panel/panel.conf /tmp/panel.conf.bak"); err != nil {
color.Red().Printfln("备份面板配置失败")
return err
}
@@ -415,18 +417,18 @@ func UpdatePanel(panelInfo PanelInfo) error {
color.Green().Printfln("备份完成")
color.Green().Printfln("清理旧版本...")
if _, err := Exec("rm -rf /www/panel/*"); err != nil {
if _, err := shell.Execf("rm -rf /www/panel/*"); err != nil {
color.Red().Printfln("清理旧版本失败")
return err
}
color.Green().Printfln("清理完成")
color.Green().Printfln("正在下载...")
if _, err := Exec("wget -T 120 -t 3 -O /www/panel/" + panelInfo.DownloadName + " " + panelInfo.DownloadUrl); err != nil {
if _, err := shell.Execf("wget -T 120 -t 3 -O /www/panel/" + panelInfo.DownloadName + " " + panelInfo.DownloadUrl); err != nil {
color.Red().Printfln("下载失败")
return err
}
if _, err := Exec("wget -T 20 -t 3 -O /www/panel/" + panelInfo.Checksums + " " + panelInfo.ChecksumsUrl); err != nil {
if _, err := shell.Execf("wget -T 20 -t 3 -O /www/panel/" + panelInfo.Checksums + " " + panelInfo.ChecksumsUrl); err != nil {
color.Red().Printfln("下载失败")
return err
}
@@ -436,7 +438,7 @@ func UpdatePanel(panelInfo PanelInfo) error {
color.Green().Printfln("下载完成")
color.Green().Printfln("校验下载文件...")
check, err := Exec("cd /www/panel && sha256sum -c " + panelInfo.Checksums + " --ignore-missing")
check, err := shell.Execf("cd /www/panel && sha256sum -c " + panelInfo.Checksums + " --ignore-missing")
if check != panelInfo.DownloadName+": OK" || err != nil {
return errors.New("下载文件校验失败")
}
@@ -447,7 +449,7 @@ func UpdatePanel(panelInfo PanelInfo) error {
color.Green().Printfln("文件校验完成")
color.Green().Printfln("更新新版本...")
if _, err = Exec("cd /www/panel && unzip -o " + panelInfo.DownloadName + " && rm -rf " + panelInfo.DownloadName); err != nil {
if _, err = shell.Execf("cd /www/panel && unzip -o " + panelInfo.DownloadName + " && rm -rf " + panelInfo.DownloadName); err != nil {
color.Red().Printfln("更新失败")
return err
}
@@ -457,15 +459,15 @@ func UpdatePanel(panelInfo PanelInfo) error {
color.Green().Printfln("更新完成")
color.Green().Printfln("恢复面板数据...")
if _, err = Exec("cp -f /tmp/panel-storage.zip /www/panel/storage/panel-storage.zip && cd /www/panel/storage && unzip -o panel-storage.zip && rm -rf panel-storage.zip"); err != nil {
if _, err = shell.Execf("cp -f /tmp/panel-storage.zip /www/panel/storage/panel-storage.zip && cd /www/panel/storage && unzip -o panel-storage.zip && rm -rf panel-storage.zip"); err != nil {
color.Red().Printfln("恢复面板数据失败")
return err
}
if _, err = Exec("cp -f /tmp/panel.conf.bak /www/panel/panel.conf"); err != nil {
if _, err = shell.Execf("cp -f /tmp/panel.conf.bak /www/panel/panel.conf"); err != nil {
color.Red().Printfln("恢复面板配置失败")
return err
}
if _, err = Exec("cp -f /www/panel/scripts/panel.sh /usr/bin/panel"); err != nil {
if _, err = shell.Execf("cp -f /www/panel/scripts/panel.sh /usr/bin/panel"); err != nil {
color.Red().Printfln("恢复面板脚本失败")
return err
}
@@ -475,28 +477,28 @@ func UpdatePanel(panelInfo PanelInfo) error {
color.Green().Printfln("恢复完成")
color.Green().Printfln("设置面板文件权限...")
_, _ = Exec("chmod -R 700 /www/panel")
_, _ = Exec("chmod -R 700 /usr/bin/panel")
_, _ = shell.Execf("chmod -R 700 /www/panel")
_, _ = shell.Execf("chmod -R 700 /usr/bin/panel")
color.Green().Printfln("设置完成")
if _, err = Exec("bash /www/panel/scripts/update_panel.sh"); err != nil {
if _, err = shell.Execf("bash /www/panel/scripts/update_panel.sh"); err != nil {
color.Red().Printfln("执行面板升级后脚本失败")
return err
}
if _, err = Exec("panel writeSetting version " + panelInfo.Version); err != nil {
if _, err = shell.Execf("panel writeSetting version " + panelInfo.Version); err != nil {
color.Red().Printfln("写入面板版本号失败")
return err
}
_, _ = Exec("rm -rf /tmp/panel-storage.zip")
_, _ = Exec("rm -rf /tmp/panel.conf.bak")
_, _ = shell.Execf("rm -rf /tmp/panel-storage.zip")
_, _ = shell.Execf("rm -rf /tmp/panel.conf.bak")
return nil
}
func RestartPanel() {
color.Green().Printfln("重启面板...")
err := ExecAsync("sleep 2 && systemctl restart panel")
err := shell.ExecfAsync("sleep 2 && systemctl restart panel")
if err != nil {
color.Red().Printfln("重启失败")
return