diff --git a/app/console/commands/panel.go b/app/console/commands/panel.go index ffa9dc324f..f1ca4ebfb5 100644 --- a/app/console/commands/panel.go +++ b/app/console/commands/panel.go @@ -125,7 +125,11 @@ func (receiver *Panel) Handle(ctx console.Context) error { return nil } - port := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`) + port, err := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`) + if err != nil { + color.Redln("获取面板端口失败") + return nil + } color.Greenln("用户名: " + user.Username) color.Greenln("密码: " + password) @@ -133,15 +137,27 @@ func (receiver *Panel) Handle(ctx console.Context) error { color.Greenln("面板入口: " + facades.Config().GetString("http.entrance")) case "getPort": - port := tools.Exec("cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}'") + port, err := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`) + if err != nil { + color.Redln("获取面板端口失败") + return nil + } + color.Greenln("面板端口: " + port) case "getEntrance": color.Greenln("面板入口: " + facades.Config().GetString("http.entrance")) case "deleteEntrance": - oldEntrance := tools.Exec(`cat /www/panel/panel.conf | grep APP_ENTRANCE | awk -F '=' '{print $2}' | tr -d '\n'`) - tools.Exec("sed -i 's!APP_ENTRANCE=" + oldEntrance + "!APP_ENTRANCE=/!g' /www/panel/panel.conf") + oldEntrance, err := tools.Exec(`cat /www/panel/panel.conf | grep APP_ENTRANCE | awk -F '=' '{print $2}' | tr -d '\n'`) + if err != nil { + color.Redln("获取面板入口失败") + return nil + } + if _, err = tools.Exec("sed -i 's!APP_ENTRANCE=" + oldEntrance + "!APP_ENTRANCE=/!g' /www/panel/panel.conf"); err != nil { + color.Redln("删除面板入口失败") + return nil + } color.Greenln("删除面板入口成功") @@ -245,7 +261,10 @@ func (receiver *Panel) Handle(ctx console.Context) error { } backupFile := path + "/" + website.Name + "_" + carbon.Now().ToShortDateTimeString() + ".zip" - tools.Exec(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`) + if _, err := tools.Exec(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`); err != nil { + color.Redln("|-备份失败: " + err.Error()) + return nil + } color.Greenln("|-备份成功") case "mysql": @@ -261,10 +280,16 @@ func (receiver *Panel) Handle(ctx console.Context) error { color.Greenln("|-目标MySQL数据库: " + name) color.Greenln("|-开始导出") - tools.Exec(`mysqldump -uroot ` + name + ` > /tmp/` + backupFile + ` 2>&1`) + if _, err = tools.Exec(`mysqldump -uroot ` + name + ` > /tmp/` + backupFile + ` 2>&1`); err != nil { + color.Redln("|-导出失败: " + err.Error()) + return nil + } color.Greenln("|-导出成功") color.Greenln("|-开始压缩") - tools.Exec("cd /tmp && zip -r " + backupFile + ".zip " + backupFile) + if _, err = tools.Exec("cd /tmp && zip -r " + backupFile + ".zip " + backupFile); err != nil { + color.Redln("|-压缩失败: " + err.Error()) + return nil + } tools.Remove("/tmp/" + backupFile) color.Greenln("|-压缩成功") color.Greenln("|-开始移动") @@ -278,7 +303,12 @@ func (receiver *Panel) Handle(ctx console.Context) error { case "postgresql": backupFile := name + "_" + carbon.Now().ToShortDateTimeString() + ".sql" - check := tools.Exec(`su - postgres -c "psql -l" 2>&1`) + check, err := tools.Exec(`su - postgres -c "psql -l" 2>&1`) + if err != nil { + color.Redln("|-获取数据库失败: " + err.Error()) + color.Greenln(hr) + return nil + } if strings.Contains(check, name) { color.Redln("|-数据库不存在") color.Greenln(hr) @@ -287,10 +317,16 @@ func (receiver *Panel) Handle(ctx console.Context) error { color.Greenln("|-目标PostgreSQL数据库: " + name) color.Greenln("|-开始导出") - tools.Exec(`su - postgres -c "pg_dump '` + name + `'" > /tmp/` + backupFile + ` 2>&1`) + if _, err = tools.Exec(`su - postgres -c "pg_dump '` + name + `'" > /tmp/` + backupFile + ` 2>&1`); err != nil { + color.Redln("|-导出失败: " + err.Error()) + return nil + } color.Greenln("|-导出成功") color.Greenln("|-开始压缩") - tools.Exec("cd /tmp && zip -r " + backupFile + ".zip " + backupFile) + if _, err = tools.Exec("cd /tmp && zip -r " + backupFile + ".zip " + backupFile); err != nil { + color.Redln("|-压缩失败: " + err.Error()) + return nil + } tools.Remove("/tmp/" + backupFile) color.Greenln("|-压缩成功") color.Greenln("|-开始移动") @@ -360,8 +396,14 @@ func (receiver *Panel) Handle(ctx console.Context) error { } backupPath := "/www/wwwlogs/" + website.Name + "_" + carbon.Now().ToShortDateTimeString() + ".log.zip" - tools.Exec(`cd /www/wwwlogs && zip -r ` + backupPath + ` ` + website.Name + ".log") - tools.Exec(`echo "" > ` + logPath) + if _, err := tools.Exec(`cd /www/wwwlogs && zip -r ` + backupPath + ` ` + website.Name + ".log"); err != nil { + color.Redln("|-备份失败: " + err.Error()) + return nil + } + if _, err := tools.Exec(`echo "" > ` + logPath); err != nil { + color.Redln("|-清空失败: " + err.Error()) + return nil + } color.Greenln("|-切割成功") color.Greenln(hr) diff --git a/app/http/controllers/controller.go b/app/http/controllers/controller.go index 8410938501..adc8ed8805 100644 --- a/app/http/controllers/controller.go +++ b/app/http/controllers/controller.go @@ -35,7 +35,7 @@ func Success(ctx http.Context, data any) http.Response { func Error(ctx http.Context, code int, message string) http.Response { return ctx.Response().Json(http.StatusOK, &ErrorResponse{ Code: code, - Message: message, + Message: "错误: " + message, }) } diff --git a/app/http/controllers/cron_controller.go b/app/http/controllers/cron_controller.go index 64a266fd11..d0b192629e 100644 --- a/app/http/controllers/cron_controller.go +++ b/app/http/controllers/cron_controller.go @@ -26,7 +26,7 @@ func NewCronController() *CronController { } // List 获取计划任务列表 -func (c *CronController) List(ctx http.Context) http.Response { +func (r *CronController) List(ctx http.Context) http.Response { limit := ctx.Request().QueryInt("limit", 10) page := ctx.Request().QueryInt("page", 1) @@ -34,7 +34,9 @@ func (c *CronController) List(ctx http.Context) http.Response { var total int64 err := facades.Orm().Query().Paginate(page, limit, &crons, &total) if err != nil { - facades.Log().Info("[面板][CronController] 查询计划任务列表失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "计划任务").With(map[string]any{ + "error": err.Error(), + }).Info("查询计划任务列表失败") return ErrorSystem(ctx) } @@ -45,7 +47,7 @@ func (c *CronController) List(ctx http.Context) http.Response { } // Add 添加计划任务 -func (c *CronController) Add(ctx http.Context) http.Response { +func (r *CronController) Add(ctx http.Context) http.Response { validator, err := ctx.Request().Validate(map[string]string{ "name": "required|min_len:1|max_len:255", "time": "required", @@ -75,7 +77,7 @@ func (c *CronController) Add(ctx http.Context) http.Response { } backupPath := ctx.Request().Input("backup_path") if len(backupPath) == 0 { - backupPath = c.setting.Get(models.SettingKeyBackupPath) + "/" + backupType + backupPath = r.setting.Get(models.SettingKeyBackupPath) + "/" + backupType } backupSave := ctx.Request().InputInt("save", 10) shell = `#!/bin/bash @@ -111,19 +113,18 @@ panel cutoff ${name} ${save} 2>&1 shellDir := "/www/server/cron/" shellLogDir := "/www/server/cron/logs/" if !tools.Exists(shellDir) { - facades.Log().Info("[面板][CronController] 计划任务目录不存在") return Error(ctx, http.StatusInternalServerError, "计划任务目录不存在") } if !tools.Exists(shellLogDir) { - facades.Log().Info("[面板][CronController] 计划任务日志目录不存在") 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 { - facades.Log().Info("[面板][CronController] 创建计划任务脚本失败 ", err) - return ErrorSystem(ctx) + return Error(ctx, http.StatusInternalServerError, err.Error()) + } + if out, err := tools.Exec("dos2unix " + shellDir + shellFile + ".sh"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) } - tools.Exec("dos2unix " + shellDir + shellFile + ".sh") var cron models.Cron cron.Name = ctx.Request().Input("name") @@ -135,11 +136,15 @@ panel cutoff ${name} ${save} 2>&1 err = facades.Orm().Query().Create(&cron) if err != nil { - facades.Log().Info("[面板][CronController] 创建计划任务失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "计划任务").With(map[string]any{ + "error": err.Error(), + }).Info("保存计划任务失败") return ErrorSystem(ctx) } - c.cron.AddToSystem(cron) + if err := r.cron.AddToSystem(cron); err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) + } return Success(ctx, http.Json{ "id": cron.ID, @@ -147,7 +152,7 @@ panel cutoff ${name} ${save} 2>&1 } // Script 获取脚本内容 -func (c *CronController) Script(ctx http.Context) http.Response { +func (r *CronController) Script(ctx http.Context) http.Response { var cron models.Cron err := facades.Orm().Query().Where("id", ctx.Request().Input("id")).FirstOrFail(&cron) if err != nil { @@ -158,7 +163,7 @@ func (c *CronController) Script(ctx http.Context) http.Response { } // Update 更新计划任务 -func (c *CronController) Update(ctx http.Context) http.Response { +func (r *CronController) Update(ctx http.Context) http.Response { validator, err := ctx.Request().Validate(map[string]string{ "name": "required|min_len:1|max_len:255", "time": "required", @@ -190,38 +195,47 @@ func (c *CronController) Update(ctx http.Context) http.Response { cron.Name = ctx.Request().Input("name") err = facades.Orm().Query().Save(&cron) if err != nil { - facades.Log().Info("[面板][CronController] 更新计划任务失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "计划任务").With(map[string]any{ + "error": err.Error(), + }).Info("更新计划任务失败") return ErrorSystem(ctx) } if err = tools.Write(cron.Shell, ctx.Request().Input("script"), 0644); err != nil { - facades.Log().Info("[面板][CronController] 更新计划任务脚本失败 ", err) - return ErrorSystem(ctx) + return Error(ctx, http.StatusInternalServerError, err.Error()) + } + if out, err := tools.Exec("dos2unix " + cron.Shell); err != nil { + return Error(ctx, http.StatusInternalServerError, out) } - tools.Exec("dos2unix " + cron.Shell) - c.cron.DeleteFromSystem(cron) + if err := r.cron.DeleteFromSystem(cron); err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) + } if cron.Status { - c.cron.AddToSystem(cron) + if err := r.cron.AddToSystem(cron); err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) + } } return Success(ctx, nil) } // Delete 删除计划任务 -func (c *CronController) Delete(ctx http.Context) http.Response { +func (r *CronController) Delete(ctx http.Context) http.Response { var cron models.Cron - err := facades.Orm().Query().Where("id", ctx.Request().Input("id")).FirstOrFail(&cron) - if err != nil { + if err := facades.Orm().Query().Where("id", ctx.Request().Input("id")).FirstOrFail(&cron); err != nil { return Error(ctx, http.StatusUnprocessableEntity, "计划任务不存在") } - c.cron.DeleteFromSystem(cron) + if err := r.cron.DeleteFromSystem(cron); err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) + } tools.Remove(cron.Shell) - _, err = facades.Orm().Query().Delete(&cron) - if err != nil { - facades.Log().Info("[面板][CronController] 删除计划任务失败 ", err) + if _, err := facades.Orm().Query().Delete(&cron); err != nil { + facades.Log().Request(ctx.Request()).Tags("面板", "计划任务").With(map[string]any{ + "error": err.Error(), + }).Info("删除计划任务失败") return ErrorSystem(ctx) } @@ -229,7 +243,7 @@ func (c *CronController) Delete(ctx http.Context) http.Response { } // Status 更新计划任务状态 -func (c *CronController) Status(ctx http.Context) http.Response { +func (r *CronController) Status(ctx http.Context) http.Response { validator, err := ctx.Request().Validate(map[string]string{ "status": "bool", }) @@ -249,23 +263,28 @@ func (c *CronController) Status(ctx http.Context) http.Response { cron.Status = ctx.Request().InputBool("status") err = facades.Orm().Query().Save(&cron) if err != nil { - facades.Log().Info("[面板][CronController] 更新计划任务状态失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "计划任务").With(map[string]any{ + "error": err.Error(), + }).Info("更新计划任务状态失败") return ErrorSystem(ctx) } - c.cron.DeleteFromSystem(cron) + if err := r.cron.DeleteFromSystem(cron); err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) + } if cron.Status { - c.cron.AddToSystem(cron) + if err := r.cron.AddToSystem(cron); err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) + } } return Success(ctx, nil) } // Log 获取计划任务日志 -func (c *CronController) Log(ctx http.Context) http.Response { +func (r *CronController) Log(ctx http.Context) http.Response { var cron models.Cron - err := facades.Orm().Query().Where("id", ctx.Request().Input("id")).FirstOrFail(&cron) - if err != nil { + if err := facades.Orm().Query().Where("id", ctx.Request().Input("id")).FirstOrFail(&cron); err != nil { return Error(ctx, http.StatusUnprocessableEntity, "计划任务不存在") } @@ -273,7 +292,10 @@ func (c *CronController) Log(ctx http.Context) http.Response { return Error(ctx, http.StatusUnprocessableEntity, "日志文件不存在") } - log := tools.Exec("tail -n 1000 " + cron.Log) + log, err := tools.Exec("tail -n 1000 " + cron.Log) + if err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) + } return Success(ctx, log) } diff --git a/app/http/controllers/info_controller.go b/app/http/controllers/info_controller.go index ea8ccbc1d0..efcc381933 100644 --- a/app/http/controllers/info_controller.go +++ b/app/http/controllers/info_controller.go @@ -34,25 +34,20 @@ func NewInfoController() *InfoController { } // Name 获取面板名称 -func (c *InfoController) Name(ctx http.Context) http.Response { - var setting models.Setting - err := facades.Orm().Query().Where("key", "name").First(&setting) - if err != nil { - facades.Log().Info("[面板][InfoController] 查询面板名称失败 ", err) - return ErrorSystem(ctx) - } - +func (r *InfoController) Name(ctx http.Context) http.Response { return Success(ctx, http.Json{ - "name": setting.Value, + "name": r.setting.Get(models.SettingKeyName), }) } // HomePlugins 获取首页插件 -func (c *InfoController) HomePlugins(ctx http.Context) http.Response { +func (r *InfoController) HomePlugins(ctx http.Context) http.Response { var plugins []models.Plugin err := facades.Orm().Query().Where("show", 1).Find(&plugins) if err != nil { - facades.Log().Info("[面板][InfoController] 查询首页插件失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "基础信息").With(map[string]any{ + "error": err.Error(), + }).Info("获取首页插件失败") return ErrorSystem(ctx) } @@ -73,12 +68,12 @@ func (c *InfoController) HomePlugins(ctx http.Context) http.Response { } // NowMonitor 获取当前监控信息 -func (c *InfoController) NowMonitor(ctx http.Context) http.Response { +func (r *InfoController) NowMonitor(ctx http.Context) http.Response { return Success(ctx, tools.GetMonitoringInfo()) } // SystemInfo 获取系统信息 -func (c *InfoController) SystemInfo(ctx http.Context) http.Response { +func (r *InfoController) SystemInfo(ctx http.Context) http.Response { monitorInfo := tools.GetMonitoringInfo() return Success(ctx, http.Json{ @@ -89,7 +84,7 @@ func (c *InfoController) SystemInfo(ctx http.Context) http.Response { } // CountInfo 获取面板统计信息 -func (c *InfoController) CountInfo(ctx http.Context) http.Response { +func (r *InfoController) CountInfo(ctx http.Context) http.Response { var websiteCount int64 err := facades.Orm().Query().Model(models.Website{}).Count(&websiteCount) if err != nil { @@ -110,26 +105,26 @@ func (c *InfoController) CountInfo(ctx http.Context) http.Response { } var databaseCount int64 if mysqlInstalled { - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if status == "active" { - rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword) + status, err := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") + if status == "active" && err == nil { + rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) type database struct { Name string `json:"name"` } db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "基础信息").With(map[string]any{ "error": err.Error(), - }).Info("[面板][InfoController] 获取数据库列表失败") + }).Info("获取数据库列表失败") databaseCount = -1 } else { defer db.Close() rows, err := db.Query("SHOW DATABASES") if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "基础信息").With(map[string]any{ "error": err.Error(), - }).Info("[面板][InfoController] 获取数据库列表失败") + }).Info("获取数据库列表失败") databaseCount = -1 } else { defer rows.Close() @@ -152,29 +147,31 @@ func (c *InfoController) CountInfo(ctx http.Context) http.Response { } } if postgresqlInstalled { - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if status == "active" { - raw := tools.Exec(`echo "\l" | su - postgres -c "psql"`) - databases := strings.Split(raw, "\n") - if len(databases) >= 4 { - databases = databases[3 : len(databases)-1] - for _, db := range databases { - parts := strings.Split(db, "|") - if len(parts) != 9 || len(strings.TrimSpace(parts[0])) == 0 || strings.TrimSpace(parts[0]) == "template0" || strings.TrimSpace(parts[0]) == "template1" || strings.TrimSpace(parts[0]) == "postgres" { - continue - } + status, err := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") + if status == "active" && err == nil { + raw, err := tools.Exec(`echo "\l" | su - postgres -c "psql"`) + if err == nil { + databases := strings.Split(raw, "\n") + if len(databases) >= 4 { + databases = databases[3 : len(databases)-1] + for _, db := range databases { + parts := strings.Split(db, "|") + if len(parts) != 9 || len(strings.TrimSpace(parts[0])) == 0 || strings.TrimSpace(parts[0]) == "template0" || strings.TrimSpace(parts[0]) == "template1" || strings.TrimSpace(parts[0]) == "postgres" { + continue + } - databaseCount++ + databaseCount++ + } } } } } var ftpCount int64 - var ftpPlugin = c.plugin.GetInstalledBySlug("pureftpd") + var ftpPlugin = r.plugin.GetInstalledBySlug("pureftpd") if ftpPlugin.ID != 0 { - listRaw := tools.Exec("pure-pw list") - if len(listRaw) != 0 { + listRaw, err := tools.Exec("pure-pw list") + if len(listRaw) != 0 && err == nil { listArr := strings.Split(listRaw, "\n") ftpCount = int64(len(listArr)) } @@ -195,7 +192,7 @@ func (c *InfoController) CountInfo(ctx http.Context) http.Response { } // InstalledDbAndPhp 获取已安装的数据库和 PHP 版本 -func (c *InfoController) InstalledDbAndPhp(ctx http.Context) http.Response { +func (r *InfoController) InstalledDbAndPhp(ctx http.Context) http.Response { var php []models.Plugin err := facades.Orm().Query().Where("slug like ?", "php%").Find(&php) if err != nil { @@ -230,7 +227,7 @@ func (c *InfoController) InstalledDbAndPhp(ctx http.Context) http.Response { continue } - phpData = append(phpData, data{Value: strings.ReplaceAll(p.Slug, "php", ""), Label: c.plugin.GetBySlug(p.Slug).Name}) + phpData = append(phpData, data{Value: strings.ReplaceAll(p.Slug, "php", ""), Label: r.plugin.GetBySlug(p.Slug).Name}) } if mysqlInstalled { @@ -247,7 +244,7 @@ func (c *InfoController) InstalledDbAndPhp(ctx http.Context) http.Response { } // CheckUpdate 检查面板更新 -func (c *InfoController) CheckUpdate(ctx http.Context) http.Response { +func (r *InfoController) CheckUpdate(ctx http.Context) http.Response { version := facades.Config().GetString("panel.version") remote, err := tools.GetLatestPanelVersion() if err != nil { @@ -266,7 +263,7 @@ func (c *InfoController) CheckUpdate(ctx http.Context) http.Response { } // UpdateInfo 获取更新信息 -func (c *InfoController) UpdateInfo(ctx http.Context) http.Response { +func (r *InfoController) UpdateInfo(ctx http.Context) http.Response { version := facades.Config().GetString("panel.version") current, err := tools.GetLatestPanelVersion() if err != nil { @@ -296,7 +293,7 @@ func (c *InfoController) UpdateInfo(ctx http.Context) http.Response { } // Update 更新面板 -func (c *InfoController) Update(ctx http.Context) http.Response { +func (r *InfoController) Update(ctx http.Context) http.Response { var task models.Task err := facades.Orm().Query().Where("status", models.TaskStatusRunning).OrWhere("status", models.TaskStatusWaiting).FirstOrFail(&task) if err == nil { @@ -305,18 +302,18 @@ func (c *InfoController) Update(ctx http.Context) http.Response { panel, err := tools.GetLatestPanelVersion() if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "基础信息").With(map[string]any{ "error": err.Error(), - }).Info("[面板][InfoController] 获取最新版本失败") + }).Info("获取最新版本失败") return Error(ctx, http.StatusInternalServerError, "获取最新版本失败") } err = tools.UpdatePanel(panel) if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "基础信息").With(map[string]any{ "error": err.Error(), - }).Info("[面板][InfoController] 更新面板失败") - return Error(ctx, http.StatusInternalServerError, "更新失败: "+err.Error()) + }).Info("更新面板失败") + return Error(ctx, http.StatusInternalServerError, err.Error()) } tools.RestartPanel() @@ -324,7 +321,7 @@ func (c *InfoController) Update(ctx http.Context) http.Response { } // Restart 重启面板 -func (c *InfoController) Restart(ctx http.Context) http.Response { +func (r *InfoController) Restart(ctx http.Context) http.Response { var task models.Task err := facades.Orm().Query().Where("status", models.TaskStatusRunning).OrWhere("status", models.TaskStatusWaiting).FirstOrFail(&task) if err == nil { diff --git a/app/http/controllers/monitor_controller.go b/app/http/controllers/monitor_controller.go index 0a107bc472..0d2f1adfd3 100644 --- a/app/http/controllers/monitor_controller.go +++ b/app/http/controllers/monitor_controller.go @@ -7,6 +7,7 @@ import ( "github.com/goravel/framework/facades" "github.com/goravel/framework/support/carbon" "github.com/spf13/cast" + "panel/app/models" "panel/app/services" ) @@ -26,7 +27,10 @@ func (r *MonitorController) Switch(ctx http.Context) http.Response { value := ctx.Request().InputBool("monitor") err := r.setting.Set(models.SettingKeyMonitor, cast.ToString(value)) if err != nil { - facades.Log().Info("[面板][MonitorController] 更新监控开关失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "资源监控").With(map[string]any{ + "monitor": value, + "error": err.Error(), + }).Info("更新监控开关失败") return ErrorSystem(ctx) } @@ -38,7 +42,10 @@ func (r *MonitorController) SaveDays(ctx http.Context) http.Response { days := ctx.Request().Input("days") err := r.setting.Set(models.SettingKeyMonitorDays, days) if err != nil { - facades.Log().Info("[面板][MonitorController] 更新监控天数失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "资源监控").With(map[string]any{ + "days": days, + "error": err.Error(), + }).Info("更新监控开关失败") return ErrorSystem(ctx) } @@ -60,7 +67,9 @@ func (r *MonitorController) SwitchAndDays(ctx http.Context) http.Response { func (r *MonitorController) Clear(ctx http.Context) http.Response { _, err := facades.Orm().Query().Where("1 = 1").Delete(&models.Monitor{}) if err != nil { - facades.Log().Info("[面板][MonitorController] 清空监控数据失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "资源监控").With(map[string]any{ + "error": err.Error(), + }).Info("清空监控数据失败") return ErrorSystem(ctx) } @@ -77,7 +86,11 @@ func (r *MonitorController) List(ctx http.Context) http.Response { var monitors []models.Monitor err := facades.Orm().Query().Where("created_at >= ?", startTime.ToDateTimeString()).Where("created_at <= ?", endTime.ToDateTimeString()).Get(&monitors) if err != nil { - facades.Log().Info("[面板][MonitorController] 查询监控数据失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "资源监控").With(map[string]any{ + "start": startTime.ToDateTimeString(), + "end": endTime.ToDateTimeString(), + "error": err.Error(), + }).Info("获取监控数据失败") return ErrorSystem(ctx) } diff --git a/app/http/controllers/plugin_controller.go b/app/http/controllers/plugin_controller.go index f35b4ca828..46523e9e71 100644 --- a/app/http/controllers/plugin_controller.go +++ b/app/http/controllers/plugin_controller.go @@ -100,7 +100,9 @@ func (r *PluginController) Install(ctx http.Context) http.Response { installedPlugin := r.plugin.GetInstalledBySlug(slug) installedPlugins, err := r.plugin.AllInstalled() if err != nil { - facades.Log().Info("[面板][PluginController] 获取已安装插件失败") + facades.Log().Request(ctx.Request()).Tags("面板", "插件中心").With(map[string]any{ + "slug": slug, + }).Info("检查插件安装状态失败") return ErrorSystem(ctx) } @@ -141,7 +143,10 @@ func (r *PluginController) Install(ctx http.Context) http.Response { task.Shell = plugin.Install + " >> /tmp/" + plugin.Slug + ".log 2>&1" task.Log = "/tmp/" + plugin.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Info("[面板][PluginController] 创建任务失败: " + err.Error()) + facades.Log().Request(ctx.Request()).Tags("面板", "插件中心").With(map[string]any{ + "slug": slug, + "err": err.Error(), + }).Info("创建任务失败") return ErrorSystem(ctx) } @@ -156,7 +161,9 @@ func (r *PluginController) Uninstall(ctx http.Context) http.Response { installedPlugin := r.plugin.GetInstalledBySlug(slug) installedPlugins, err := r.plugin.AllInstalled() if err != nil { - facades.Log().Info("[面板][PluginController] 获取已安装插件失败") + facades.Log().Request(ctx.Request()).Tags("面板", "插件中心").With(map[string]any{ + "slug": slug, + }).Info("检查插件安装状态失败") return ErrorSystem(ctx) } @@ -197,7 +204,10 @@ func (r *PluginController) Uninstall(ctx http.Context) http.Response { task.Shell = plugin.Uninstall + " >> /tmp/" + plugin.Slug + ".log 2>&1" task.Log = "/tmp/" + plugin.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Info("[面板][PluginController] 创建任务失败: " + err.Error()) + facades.Log().Request(ctx.Request()).Tags("面板", "插件中心").With(map[string]any{ + "slug": slug, + "err": err.Error(), + }).Info("创建任务失败") return ErrorSystem(ctx) } @@ -212,7 +222,9 @@ func (r *PluginController) Update(ctx http.Context) http.Response { installedPlugin := r.plugin.GetInstalledBySlug(slug) installedPlugins, err := r.plugin.AllInstalled() if err != nil { - facades.Log().Info("[面板][PluginController] 获取已安装插件失败") + facades.Log().Request(ctx.Request()).Tags("面板", "插件中心").With(map[string]any{ + "slug": slug, + }).Info("检查插件安装状态失败") return ErrorSystem(ctx) } @@ -253,7 +265,10 @@ func (r *PluginController) Update(ctx http.Context) http.Response { task.Shell = plugin.Update + " >> /tmp/" + plugin.Slug + ".log 2>&1" task.Log = "/tmp/" + plugin.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Info("[面板][PluginController] 创建任务失败: " + err.Error()) + facades.Log().Request(ctx.Request()).Tags("面板", "插件中心").With(map[string]any{ + "slug": slug, + "err": err.Error(), + }).Info("创建任务失败") return ErrorSystem(ctx) } @@ -268,7 +283,10 @@ func (r *PluginController) UpdateShow(ctx http.Context) http.Response { var plugin models.Plugin if err := facades.Orm().Query().Where("slug", slug).First(&plugin); err != nil { - facades.Log().Info("[面板][PluginController] 查询插件失败: " + err.Error()) + facades.Log().Request(ctx.Request()).Tags("面板", "插件中心").With(map[string]any{ + "slug": slug, + "err": err.Error(), + }).Info("获取插件失败") return ErrorSystem(ctx) } if plugin.ID == 0 { @@ -277,7 +295,10 @@ func (r *PluginController) UpdateShow(ctx http.Context) http.Response { plugin.Show = show if err := facades.Orm().Query().Save(&plugin); err != nil { - facades.Log().Info("[面板][PluginController] 更新插件失败: " + err.Error()) + facades.Log().Request(ctx.Request()).Tags("面板", "插件中心").With(map[string]any{ + "slug": slug, + "err": err.Error(), + }).Info("更新插件失败") return ErrorSystem(ctx) } diff --git a/app/http/controllers/plugins/fail2ban_controller.go b/app/http/controllers/plugins/fail2ban_controller.go index 88601df78f..ef9c427e2a 100644 --- a/app/http/controllers/plugins/fail2ban_controller.go +++ b/app/http/controllers/plugins/fail2ban_controller.go @@ -31,16 +31,12 @@ func (r *Fail2banController) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("fail2ban") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } // Reload 重载配置 @@ -50,17 +46,11 @@ func (r *Fail2banController) Reload(ctx http.Context) http.Response { return check } - tools.Exec("systemctl reload fail2ban") - status := tools.Exec("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败") + if _, err := tools.Exec("systemctl reload fail2ban"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载配置失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Restart 重启服务 @@ -70,17 +60,11 @@ func (r *Fail2banController) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart fail2ban") - status := tools.Exec("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败") + if err := tools.ServiceRestart("fail2ban"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启服务失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Start 启动服务 @@ -90,17 +74,11 @@ func (r *Fail2banController) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start fail2ban") - status := tools.Exec("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败") + if err := tools.ServiceStart("fail2ban"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动服务失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Stop 停止服务 @@ -110,17 +88,15 @@ func (r *Fail2banController) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop fail2ban") - status := tools.Exec("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + if err := tools.ServiceStop("fail2ban"); err != nil { + return nil + } + status, err := tools.ServiceStatus("fail2ban") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, !status) } // List 所有 Fail2ban 规则 @@ -289,6 +265,7 @@ ignoreregex = var logPath string var filter string var port string + var err error switch jailName { case "ssh": if tools.IsDebian() { @@ -297,19 +274,19 @@ ignoreregex = logPath = "/var/log/secure" } filter = "sshd" - port = tools.Exec("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'") + port, err = tools.Exec("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'") case "mysql": logPath = "/www/server/mysql/mysql-error.log" filter = "mysqld-auth" - port = tools.Exec("cat /www/server/mysql/conf/my.cnf | grep 'port' | head -n 1 | awk '{print $3}'") + port, err = tools.Exec("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 = tools.Exec(`cat /www/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`) + port, err = tools.Exec(`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, "未知服务") } - if len(port) == 0 { + if len(port) == 0 || err != nil { return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取服务端口失败,请检查是否安装") } @@ -332,7 +309,10 @@ logpath = ` + logPath + ` } } - tools.Exec("fail2ban-client reload") + if _, err := tools.Exec("fail2ban-client reload"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载配置失败") + } + return controllers.Success(ctx, nil) } @@ -356,7 +336,10 @@ func (r *Fail2banController) Delete(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusInternalServerError, "写入Fail2ban规则失败") } - tools.Exec("fail2ban-client reload") + if _, err := tools.Exec("fail2ban-client reload"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载配置失败") + } + return controllers.Success(ctx, nil) } @@ -372,9 +355,18 @@ func (r *Fail2banController) BanList(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "缺少参数") } - currentlyBan := tools.Exec(`fail2ban-client status ` + name + ` | grep "Currently banned" | awk '{print $4}'`) - totalBan := tools.Exec(`fail2ban-client status ` + name + ` | grep "Total banned" | awk '{print $4}'`) - bannedIp := tools.Exec(`fail2ban-client status ` + name + ` | grep "Banned IP list" | awk -F ":" '{print $2}'`) + currentlyBan, err := tools.Exec(`fail2ban-client status ` + name + ` | grep "Currently banned" | awk '{print $4}'`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取封禁列表失败") + } + totalBan, err := tools.Exec(`fail2ban-client status ` + name + ` | grep "Total banned" | awk '{print $4}'`) + 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}'`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取封禁列表失败") + } bannedIpList := strings.Split(bannedIp, " ") var list []map[string]string @@ -410,7 +402,10 @@ func (r *Fail2banController) Unban(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "缺少参数") } - tools.Exec("fail2ban-client set " + name + " unbanip " + ip) + if _, err := tools.Exec("fail2ban-client set " + name + " unbanip " + ip); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "解封失败") + } + return controllers.Success(ctx, nil) } @@ -438,7 +433,10 @@ func (r *Fail2banController) SetWhiteList(ctx http.Context) http.Response { if err := tools.Write("/etc/fail2ban/jail.local", raw, 0644); err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "写入Fail2ban规则失败") } - tools.Exec("fail2ban-client reload") + + if _, err := tools.Exec("fail2ban-client reload"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载配置失败") + } return controllers.Success(ctx, nil) } diff --git a/app/http/controllers/plugins/mysql57_controller.go b/app/http/controllers/plugins/mysql57_controller.go index 6a4570188c..d090d87af8 100644 --- a/app/http/controllers/plugins/mysql57_controller.go +++ b/app/http/controllers/plugins/mysql57_controller.go @@ -4,10 +4,8 @@ import ( "database/sql" "fmt" "regexp" - "strings" "github.com/goravel/framework/contracts/http" - "github.com/goravel/framework/facades" "github.com/spf13/cast" "panel/app/http/controllers" @@ -35,16 +33,12 @@ func (r *Mysql57Controller) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("mysqld") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } // Reload 重载配置 @@ -54,17 +48,11 @@ func (r *Mysql57Controller) Reload(ctx http.Context) http.Response { return check } - tools.Exec("systemctl reload mysqld") - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") + if err := tools.ServiceReload("mysqld"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载MySQL失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Restart 重启服务 @@ -74,17 +62,11 @@ func (r *Mysql57Controller) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart mysqld") - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") + if err := tools.ServiceRestart("mysqld"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启MySQL服务失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Start 启动服务 @@ -94,17 +76,11 @@ func (r *Mysql57Controller) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start mysqld") - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") + if err := tools.ServiceStart("mysqld"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动MySQL服务失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Stop 停止服务 @@ -114,17 +90,11 @@ func (r *Mysql57Controller) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop mysqld") - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") + if err := tools.ServiceStop("mysqld"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止MySQL服务失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // GetConfig 获取配置 @@ -174,16 +144,16 @@ func (r *Mysql57Controller) Load(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "MySQL root密码为空") } - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if status != "active" { - return controllers.Error(ctx, http.StatusInternalServerError, "MySQL 已停止运行") + status, err := tools.ServiceStatus("mysqld") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") } - - raw := tools.Exec("/www/server/mysql/bin/mysqladmin -uroot -p" + rootPassword + " extended-status 2>&1") - if strings.Contains(raw, "Access denied for user") { - return controllers.Error(ctx, http.StatusUnprocessableEntity, "MySQL root密码错误") + if !status { + return controllers.Error(ctx, http.StatusInternalServerError, "MySQL 未运行") } - if !strings.Contains(raw, "Uptime") { + + raw, err := tools.Exec("/www/server/mysql/bin/mysqladmin -uroot -p" + rootPassword + " extended-status 2>&1") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL负载失败") } @@ -244,7 +214,11 @@ func (r *Mysql57Controller) ErrorLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/mysql/mysql-error.log")) + log, err := tools.Exec("tail -n 100 /www/server/mysql/mysql-error.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -255,8 +229,11 @@ func (r *Mysql57Controller) ClearErrorLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/mysql/mysql-error.log") - return controllers.Success(ctx, "清空错误日志成功") + if out, err := tools.Exec("echo '' > /www/server/mysql/mysql-error.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + + return controllers.Success(ctx, nil) } // SlowLog 获取慢查询日志 @@ -266,7 +243,11 @@ func (r *Mysql57Controller) SlowLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/mysql/mysql-slow.log")) + log, err := tools.Exec("tail -n 100 /www/server/mysql/mysql-slow.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -277,8 +258,10 @@ func (r *Mysql57Controller) ClearSlowLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/mysql/mysql-slow.log") - return controllers.Success(ctx, "清空慢查询日志成功") + if out, err := tools.Exec("echo '' > /www/server/mysql/mysql-slow.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } // GetRootPassword 获取root密码 @@ -303,11 +286,11 @@ func (r *Mysql57Controller) SetRootPassword(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("mysqld") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") } - if status != "active" { + if !status { return controllers.Error(ctx, http.StatusInternalServerError, "MySQL 未运行") } @@ -318,17 +301,25 @@ func (r *Mysql57Controller) SetRootPassword(ctx http.Context) http.Response { oldRootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) if oldRootPassword != rootPassword { - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + rootPassword + "';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"FLUSH PRIVILEGES;\"") + if _, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + rootPassword + "';\""); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "设置root密码失败") + } + if _, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "设置root密码失败") + } err := r.setting.Set(models.SettingKeyMysqlRootPassword, rootPassword) if err != nil { - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + oldRootPassword + "';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"") + if _, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + oldRootPassword + "';\""); err != nil { + return nil + } + if _, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil { + return nil + } return controllers.Error(ctx, http.StatusInternalServerError, "设置root密码失败") } } - return controllers.Success(ctx, "设置root密码成功") + return controllers.Success(ctx, nil) } // DatabaseList 获取数据库列表 @@ -345,15 +336,13 @@ func (r *Mysql57Controller) DatabaseList(ctx http.Context) http.Response { db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") if err != nil { - facades.Log().Info("[MySQL57] 连接数据库失败" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } defer db.Close() rows, err := db.Query("SHOW DATABASES") if err != nil { - facades.Log().Info("[MySQL57] 获取数据库列表失败" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } defer rows.Close() @@ -369,7 +358,6 @@ func (r *Mysql57Controller) DatabaseList(ctx http.Context) http.Response { } if err := rows.Err(); err != nil { - facades.Log().Info("[MySQL57] 获取数据库列表失败" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") } @@ -418,12 +406,20 @@ func (r *Mysql57Controller) AddDatabase(ctx http.Context) http.Response { user := ctx.Request().Input("user") password := ctx.Request().Input("password") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE DATABASE IF NOT EXISTS " + database + " DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"") + 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 { + 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 { + 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 { + 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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "添加数据库成功") + return controllers.Success(ctx, nil) } // DeleteDatabase 删除数据库 @@ -445,9 +441,11 @@ func (r *Mysql57Controller) DeleteDatabase(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) database := ctx.Request().Input("database") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP DATABASE IF EXISTS " + database + ";\"") + if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP DATABASE IF EXISTS " + database + ";\""); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "删除数据库成功") + return controllers.Success(ctx, nil) } // BackupList 获取备份列表 @@ -459,8 +457,7 @@ func (r *Mysql57Controller) BackupList(ctx http.Context) http.Response { backupList, err := r.backup.MysqlList() if err != nil { - facades.Log().Info("[MySQL57] 获取备份列表失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "获取备份列表失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } page := ctx.Request().QueryInt("page", 1) @@ -512,7 +509,7 @@ func (r *Mysql57Controller) UploadBackup(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "上传文件失败") } - return controllers.Success(ctx, "上传文件成功") + return controllers.Success(ctx, nil) } // CreateBackup 创建备份 @@ -535,11 +532,10 @@ func (r *Mysql57Controller) CreateBackup(ctx http.Context) http.Response { database := ctx.Request().Input("database") err = r.backup.MysqlBackup(database) if err != nil { - facades.Log().Info("[MYSQL57] 创建备份失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "创建备份失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } - return controllers.Success(ctx, "备份成功") + return controllers.Success(ctx, nil) } // DeleteBackup 删除备份 @@ -563,7 +559,7 @@ func (r *Mysql57Controller) DeleteBackup(ctx http.Context) http.Response { fileName := ctx.Request().Input("name") tools.Remove(backupPath + "/" + fileName) - return controllers.Success(ctx, "删除备份成功") + return controllers.Success(ctx, nil) } // RestoreBackup 还原备份 @@ -586,11 +582,10 @@ func (r *Mysql57Controller) RestoreBackup(ctx http.Context) http.Response { err = r.backup.MysqlRestore(ctx.Request().Input("database"), ctx.Request().Input("backup")) if err != nil { - facades.Log().Info("[MYSQL57] 还原失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "还原失败: "+err.Error()) + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } - return controllers.Success(ctx, "还原成功") + return controllers.Success(ctx, nil) } // UserList 用户列表 @@ -609,15 +604,13 @@ func (r *Mysql57Controller) UserList(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") if err != nil { - facades.Log().Info("[MYSQL57] 连接数据库失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } defer db.Close() rows, err := db.Query("SELECT user, host FROM mysql.user") if err != nil { - facades.Log().Info("[MYSQL57] 查询数据库失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "查询数据库失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } defer rows.Close() @@ -702,11 +695,17 @@ func (r *Mysql57Controller) AddUser(ctx http.Context) http.Response { user := ctx.Request().Input("user") password := ctx.Request().Input("password") database := ctx.Request().Input("database") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + ";'\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"") + if out, err := tools.Exec("/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 { + 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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "添加成功") + return controllers.Success(ctx, nil) } // DeleteUser 删除用户 @@ -728,9 +727,11 @@ func (r *Mysql57Controller) DeleteUser(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) user := ctx.Request().Input("user") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP USER '" + user + "'@'localhost';\"") + if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP USER '" + user + "'@'localhost';\""); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "删除成功") + return controllers.Success(ctx, nil) } // SetUserPassword 设置用户密码 @@ -754,10 +755,14 @@ func (r *Mysql57Controller) SetUserPassword(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) user := ctx.Request().Input("user") password := ctx.Request().Input("password") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"") + if out, err := tools.Exec("/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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "修改成功") + return controllers.Success(ctx, nil) } // SetUserPrivileges 设置用户权限 @@ -781,9 +786,15 @@ func (r *Mysql57Controller) SetUserPrivileges(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) user := ctx.Request().Input("user") database := ctx.Request().Input("database") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"REVOKE ALL PRIVILEGES ON *.* FROM '" + user + "'@'localhost';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"") + if out, err := tools.Exec("/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 { + 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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "修改成功") + return controllers.Success(ctx, nil) } diff --git a/app/http/controllers/plugins/mysql80_controller.go b/app/http/controllers/plugins/mysql80_controller.go index 729fd78d47..932c82b7cb 100644 --- a/app/http/controllers/plugins/mysql80_controller.go +++ b/app/http/controllers/plugins/mysql80_controller.go @@ -4,10 +4,8 @@ import ( "database/sql" "fmt" "regexp" - "strings" "github.com/goravel/framework/contracts/http" - "github.com/goravel/framework/facades" "github.com/spf13/cast" "panel/app/http/controllers" @@ -35,16 +33,12 @@ func (r *Mysql80Controller) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("mysqld") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } // Reload 重载配置 @@ -54,17 +48,11 @@ func (r *Mysql80Controller) Reload(ctx http.Context) http.Response { return check } - tools.Exec("systemctl reload mysqld") - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") + if err := tools.ServiceReload("mysqld"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载MySQL配置失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Restart 重启服务 @@ -74,17 +62,11 @@ func (r *Mysql80Controller) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart mysqld") - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") + if err := tools.ServiceRestart("mysqld"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启MySQL服务失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Start 启动服务 @@ -94,17 +76,11 @@ func (r *Mysql80Controller) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start mysqld") - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") + if err := tools.ServiceStart("mysqld"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动MySQL服务失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Stop 停止服务 @@ -114,17 +90,11 @@ func (r *Mysql80Controller) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop mysqld") - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") + if err := tools.ServiceStop("mysqld"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止MySQL服务失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // GetConfig 获取配置 @@ -174,16 +144,16 @@ func (r *Mysql80Controller) Load(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "MySQL root密码为空") } - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if status != "active" { - return controllers.Error(ctx, http.StatusInternalServerError, "MySQL 已停止运行") + status, err := tools.ServiceStatus("mysqld") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") } - - raw := tools.Exec("/www/server/mysql/bin/mysqladmin -uroot -p" + rootPassword + " extended-status 2>&1") - if strings.Contains(raw, "Access denied for user") { - return controllers.Error(ctx, http.StatusUnprocessableEntity, "MySQL root密码错误") + if !status { + return controllers.Error(ctx, http.StatusInternalServerError, "MySQL 未运行") } - if !strings.Contains(raw, "Uptime") { + + raw, err := tools.Exec("/www/server/mysql/bin/mysqladmin -uroot -p" + rootPassword + " extended-status 2>&1") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL负载失败") } @@ -244,7 +214,11 @@ func (r *Mysql80Controller) ErrorLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/mysql/mysql-error.log")) + log, err := tools.Exec("tail -n 100 /www/server/mysql/mysql-error.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -255,8 +229,11 @@ func (r *Mysql80Controller) ClearErrorLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/mysql/mysql-error.log") - return controllers.Success(ctx, "清空错误日志成功") + if out, err := tools.Exec("echo '' > /www/server/mysql/mysql-error.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + + return controllers.Success(ctx, nil) } // SlowLog 获取慢查询日志 @@ -266,7 +243,11 @@ func (r *Mysql80Controller) SlowLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/mysql/mysql-slow.log")) + log, err := tools.Exec("tail -n 100 /www/server/mysql/mysql-slow.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -277,8 +258,10 @@ func (r *Mysql80Controller) ClearSlowLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/mysql/mysql-slow.log") - return controllers.Success(ctx, "清空慢查询日志成功") + if out, err := tools.Exec("echo '' > /www/server/mysql/mysql-slow.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } // GetRootPassword 获取root密码 @@ -303,11 +286,11 @@ func (r *Mysql80Controller) SetRootPassword(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("mysqld") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") } - if status != "active" { + if !status { return controllers.Error(ctx, http.StatusInternalServerError, "MySQL 未运行") } @@ -318,17 +301,25 @@ func (r *Mysql80Controller) SetRootPassword(ctx http.Context) http.Response { oldRootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) if oldRootPassword != rootPassword { - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + rootPassword + "';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"FLUSH PRIVILEGES;\"") + if _, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + rootPassword + "';\""); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "设置root密码失败") + } + if _, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "设置root密码失败") + } err := r.setting.Set(models.SettingKeyMysqlRootPassword, rootPassword) if err != nil { - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + oldRootPassword + "';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"") + if _, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + oldRootPassword + "';\""); err != nil { + return nil + } + if _, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\""); err != nil { + return nil + } return controllers.Error(ctx, http.StatusInternalServerError, "设置root密码失败") } } - return controllers.Success(ctx, "设置root密码成功") + return controllers.Success(ctx, nil) } // DatabaseList 获取数据库列表 @@ -345,15 +336,13 @@ func (r *Mysql80Controller) DatabaseList(ctx http.Context) http.Response { db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") if err != nil { - facades.Log().Info("[MySQL80] 连接数据库失败" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } defer db.Close() rows, err := db.Query("SHOW DATABASES") if err != nil { - facades.Log().Info("[MySQL80] 获取数据库列表失败" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } defer rows.Close() @@ -369,7 +358,6 @@ func (r *Mysql80Controller) DatabaseList(ctx http.Context) http.Response { } if err := rows.Err(); err != nil { - facades.Log().Info("[MySQL80] 获取数据库列表失败" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") } @@ -418,12 +406,20 @@ func (r *Mysql80Controller) AddDatabase(ctx http.Context) http.Response { user := ctx.Request().Input("user") password := ctx.Request().Input("password") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE DATABASE IF NOT EXISTS " + database + " DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"") + 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 { + 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 { + 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 { + 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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "添加数据库成功") + return controllers.Success(ctx, nil) } // DeleteDatabase 删除数据库 @@ -445,9 +441,11 @@ func (r *Mysql80Controller) DeleteDatabase(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) database := ctx.Request().Input("database") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP DATABASE IF EXISTS " + database + ";\"") + if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP DATABASE IF EXISTS " + database + ";\""); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "删除数据库成功") + return controllers.Success(ctx, nil) } // BackupList 获取备份列表 @@ -459,8 +457,7 @@ func (r *Mysql80Controller) BackupList(ctx http.Context) http.Response { backupList, err := r.backup.MysqlList() if err != nil { - facades.Log().Info("[MySQL80] 获取备份列表失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "获取备份列表失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } page := ctx.Request().QueryInt("page", 1) @@ -512,7 +509,7 @@ func (r *Mysql80Controller) UploadBackup(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "上传文件失败") } - return controllers.Success(ctx, "上传文件成功") + return controllers.Success(ctx, nil) } // CreateBackup 创建备份 @@ -535,11 +532,10 @@ func (r *Mysql80Controller) CreateBackup(ctx http.Context) http.Response { database := ctx.Request().Input("database") err = r.backup.MysqlBackup(database) if err != nil { - facades.Log().Info("[MYSQL80] 创建备份失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "创建备份失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } - return controllers.Success(ctx, "备份成功") + return controllers.Success(ctx, nil) } // DeleteBackup 删除备份 @@ -563,7 +559,7 @@ func (r *Mysql80Controller) DeleteBackup(ctx http.Context) http.Response { fileName := ctx.Request().Input("name") tools.Remove(backupPath + "/" + fileName) - return controllers.Success(ctx, "删除备份成功") + return controllers.Success(ctx, nil) } // RestoreBackup 还原备份 @@ -586,11 +582,10 @@ func (r *Mysql80Controller) RestoreBackup(ctx http.Context) http.Response { err = r.backup.MysqlRestore(ctx.Request().Input("database"), ctx.Request().Input("backup")) if err != nil { - facades.Log().Info("[MYSQL80] 还原失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "还原失败: "+err.Error()) + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } - return controllers.Success(ctx, "还原成功") + return controllers.Success(ctx, nil) } // UserList 用户列表 @@ -609,15 +604,13 @@ func (r *Mysql80Controller) UserList(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") if err != nil { - facades.Log().Info("[MYSQL80] 连接数据库失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } defer db.Close() rows, err := db.Query("SELECT user, host FROM mysql.user") if err != nil { - facades.Log().Info("[MYSQL80] 查询数据库失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "查询数据库失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } defer rows.Close() @@ -702,11 +695,17 @@ func (r *Mysql80Controller) AddUser(ctx http.Context) http.Response { user := ctx.Request().Input("user") password := ctx.Request().Input("password") database := ctx.Request().Input("database") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + ";'\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"") + if out, err := tools.Exec("/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 { + 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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "添加成功") + return controllers.Success(ctx, nil) } // DeleteUser 删除用户 @@ -728,9 +727,11 @@ func (r *Mysql80Controller) DeleteUser(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) user := ctx.Request().Input("user") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP USER '" + user + "'@'localhost';\"") + if out, err := tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP USER '" + user + "'@'localhost';\""); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "删除成功") + return controllers.Success(ctx, nil) } // SetUserPassword 设置用户密码 @@ -754,10 +755,14 @@ func (r *Mysql80Controller) SetUserPassword(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) user := ctx.Request().Input("user") password := ctx.Request().Input("password") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"") + if out, err := tools.Exec("/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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "修改成功") + return controllers.Success(ctx, nil) } // SetUserPrivileges 设置用户权限 @@ -781,9 +786,15 @@ func (r *Mysql80Controller) SetUserPrivileges(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) user := ctx.Request().Input("user") database := ctx.Request().Input("database") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"REVOKE ALL PRIVILEGES ON *.* FROM '" + user + "'@'localhost';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"") - tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"") + if out, err := tools.Exec("/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 { + 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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } - return controllers.Success(ctx, "修改成功") + return controllers.Success(ctx, nil) } diff --git a/app/http/controllers/plugins/openresty_controller.go b/app/http/controllers/plugins/openresty_controller.go index d8934a0f83..319a38ec4c 100644 --- a/app/http/controllers/plugins/openresty_controller.go +++ b/app/http/controllers/plugins/openresty_controller.go @@ -5,7 +5,6 @@ import ( "time" "github.com/goravel/framework/contracts/http" - "github.com/goravel/framework/facades" "github.com/imroc/req/v3" "github.com/spf13/cast" @@ -30,16 +29,12 @@ func (r *OpenRestyController) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("openresty") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } // Reload 重载配置 @@ -49,17 +44,11 @@ func (r *OpenRestyController) Reload(ctx http.Context) http.Response { return check } - tools.Exec("systemctl reload openresty") - status := tools.Exec("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty状态失败") + if err := tools.ServiceReload("openresty"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载OpenResty失败") } - if status == "active" { - return controllers.Success(ctx, "重载OpenResty成功") - } else { - return controllers.Error(ctx, 1, "重载OpenResty失败: "+status) - } + return controllers.Success(ctx, nil) } // Start 启动OpenResty @@ -69,17 +58,11 @@ func (r *OpenRestyController) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start openresty") - status := tools.Exec("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty状态失败") + if err := tools.ServiceStart("openresty"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动OpenResty失败") } - if status == "active" { - return controllers.Success(ctx, "启动OpenResty成功") - } else { - return controllers.Error(ctx, 1, "启动OpenResty失败: "+status) - } + return controllers.Success(ctx, nil) } // Stop 停止OpenResty @@ -89,17 +72,11 @@ func (r *OpenRestyController) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop openresty") - status := tools.Exec("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty状态失败") + if err := tools.ServiceStop("openresty"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止OpenResty失败") } - if status != "active" { - return controllers.Success(ctx, "停止OpenResty成功") - } else { - return controllers.Error(ctx, 1, "停止OpenResty失败: "+status) - } + return controllers.Success(ctx, nil) } // Restart 重启OpenResty @@ -109,17 +86,11 @@ func (r *OpenRestyController) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart openresty") - status := tools.Exec("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty状态失败") + if err := tools.ServiceRestart("openresty"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启OpenResty失败") } - if status == "active" { - return controllers.Success(ctx, "重启OpenResty成功") - } else { - return controllers.Error(ctx, 1, "重启OpenResty失败: "+status) - } + return controllers.Success(ctx, nil) } // GetConfig 获取配置 @@ -167,7 +138,11 @@ func (r *OpenRestyController) ErrorLog(ctx http.Context) http.Response { return controllers.Success(ctx, "") } - out := tools.Exec("tail -n 100 /www/wwwlogs/nginx_error.log") + out, err := tools.Exec("tail -n 100 /www/wwwlogs/nginx_error.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, out) } @@ -178,8 +153,11 @@ func (r *OpenRestyController) ClearErrorLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/wwwlogs/nginx_error.log") - return controllers.Success(ctx, "清空OpenResty错误日志成功") + if out, err := tools.Exec("echo '' > /www/wwwlogs/nginx_error.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + + return controllers.Success(ctx, nil) } // Load 获取负载 @@ -192,7 +170,6 @@ func (r *OpenRestyController) Load(ctx http.Context) http.Response { client := req.C().SetTimeout(10 * time.Second) resp, err := client.R().Get("http://127.0.0.1/nginx_status") if err != nil || !resp.IsSuccessState() { - facades.Log().Info("[OpenResty] 获取OpenResty负载失败: " + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty负载失败") } @@ -203,13 +180,19 @@ func (r *OpenRestyController) Load(ctx http.Context) http.Response { } var data []nginxStatus - workers := tools.Exec("ps aux | grep nginx | grep 'worker process' | wc -l") + workers, err := tools.Exec("ps aux | grep nginx | grep 'worker process' | wc -l") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty负载失败") + } data = append(data, nginxStatus{ Name: "工作进程", Value: workers, }) - out := tools.Exec("ps aux | grep nginx | grep 'worker process' | awk '{memsum+=$6};END {print memsum}'") + out, err := tools.Exec("ps aux | grep nginx | grep 'worker process' | awk '{memsum+=$6};END {print memsum}'") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty负载失败") + } mem := tools.FormatBytes(cast.ToFloat64(out)) data = append(data, nginxStatus{ Name: "内存占用", diff --git a/app/http/controllers/plugins/php74_controller.go b/app/http/controllers/plugins/php74_controller.go index cbd4b48936..b9da5f765b 100644 --- a/app/http/controllers/plugins/php74_controller.go +++ b/app/http/controllers/plugins/php74_controller.go @@ -36,16 +36,12 @@ func (r *Php74Controller) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("php-fpm-" + r.version) + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } func (r *Php74Controller) Reload(ctx http.Context) http.Response { @@ -54,18 +50,11 @@ func (r *Php74Controller) Reload(ctx http.Context) http.Response { return check } - tools.Exec("systemctl reload php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceReload("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php74Controller) Start(ctx http.Context) http.Response { @@ -74,18 +63,11 @@ func (r *Php74Controller) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceStart("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php74Controller) Stop(ctx http.Context) http.Response { @@ -94,18 +76,11 @@ func (r *Php74Controller) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceStop("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止PHP-"+r.version+"失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php74Controller) Restart(ctx http.Context) http.Response { @@ -114,18 +89,11 @@ func (r *Php74Controller) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceRestart("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php74Controller) GetConfig(ctx http.Context) http.Response { @@ -193,7 +161,11 @@ func (r *Php74Controller) ErrorLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/php-fpm.log")) + log, err := tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/php-fpm.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -203,7 +175,11 @@ func (r *Php74Controller) SlowLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/slow.log")) + log, err := tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/slow.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -213,8 +189,11 @@ func (r *Php74Controller) ClearErrorLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/php-fpm.log") - return controllers.Success(ctx, true) + if out, err := tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/php-fpm.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + + return controllers.Success(ctx, nil) } func (r *Php74Controller) ClearSlowLog(ctx http.Context) http.Response { @@ -223,8 +202,10 @@ func (r *Php74Controller) ClearSlowLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/slow.log") - return controllers.Success(ctx, true) + if out, err := tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/slow.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } func (r *Php74Controller) GetExtensionList(ctx http.Context) http.Response { @@ -350,9 +331,12 @@ func (r *Php74Controller) GetExtensions() []PHPExtension { Installed: false, }) - raw := tools.Exec("/www/server/php/" + r.version + "/bin/php -m") - rawExtensionList := strings.Split(raw, "\n") + raw, err := tools.Exec("/www/server/php/" + r.version + "/bin/php -m") + if err != nil { + return extensions + } + rawExtensionList := strings.Split(raw, "\n") for _, item := range rawExtensionList { if !strings.Contains(item, "[") && item != "" { for i := range extensions { diff --git a/app/http/controllers/plugins/php80_controller.go b/app/http/controllers/plugins/php80_controller.go index 86db189a2e..be0c0abcde 100644 --- a/app/http/controllers/plugins/php80_controller.go +++ b/app/http/controllers/plugins/php80_controller.go @@ -36,16 +36,12 @@ func (r *Php80Controller) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("php-fpm-" + r.version) + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } func (r *Php80Controller) Reload(ctx http.Context) http.Response { @@ -54,18 +50,11 @@ func (r *Php80Controller) Reload(ctx http.Context) http.Response { return check } - tools.Exec("systemctl reload php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceReload("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php80Controller) Start(ctx http.Context) http.Response { @@ -74,18 +63,11 @@ func (r *Php80Controller) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceStart("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php80Controller) Stop(ctx http.Context) http.Response { @@ -94,18 +76,11 @@ func (r *Php80Controller) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceStop("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止PHP-"+r.version+"失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php80Controller) Restart(ctx http.Context) http.Response { @@ -114,18 +89,11 @@ func (r *Php80Controller) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceRestart("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php80Controller) GetConfig(ctx http.Context) http.Response { @@ -193,7 +161,11 @@ func (r *Php80Controller) ErrorLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/php-fpm.log")) + log, err := tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/php-fpm.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -203,7 +175,11 @@ func (r *Php80Controller) SlowLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/slow.log")) + log, err := tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/slow.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -213,8 +189,11 @@ func (r *Php80Controller) ClearErrorLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/php-fpm.log") - return controllers.Success(ctx, true) + if out, err := tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/php-fpm.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + + return controllers.Success(ctx, nil) } func (r *Php80Controller) ClearSlowLog(ctx http.Context) http.Response { @@ -223,8 +202,10 @@ func (r *Php80Controller) ClearSlowLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/slow.log") - return controllers.Success(ctx, true) + if out, err := tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/slow.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } func (r *Php80Controller) GetExtensionList(ctx http.Context) http.Response { @@ -350,9 +331,12 @@ func (r *Php80Controller) GetExtensions() []PHPExtension { Installed: false, }) - raw := tools.Exec("/www/server/php/" + r.version + "/bin/php -m") - rawExtensionList := strings.Split(raw, "\n") + raw, err := tools.Exec("/www/server/php/" + r.version + "/bin/php -m") + if err != nil { + return extensions + } + rawExtensionList := strings.Split(raw, "\n") for _, item := range rawExtensionList { if !strings.Contains(item, "[") && item != "" { for i := range extensions { diff --git a/app/http/controllers/plugins/php81_controller.go b/app/http/controllers/plugins/php81_controller.go index 36a80271c9..63755d65de 100644 --- a/app/http/controllers/plugins/php81_controller.go +++ b/app/http/controllers/plugins/php81_controller.go @@ -36,16 +36,12 @@ func (r *Php81Controller) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("php-fpm-" + r.version) + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } func (r *Php81Controller) Reload(ctx http.Context) http.Response { @@ -54,18 +50,11 @@ func (r *Php81Controller) Reload(ctx http.Context) http.Response { return check } - tools.Exec("systemctl reload php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceReload("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php81Controller) Start(ctx http.Context) http.Response { @@ -74,18 +63,11 @@ func (r *Php81Controller) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceStart("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php81Controller) Stop(ctx http.Context) http.Response { @@ -94,18 +76,11 @@ func (r *Php81Controller) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceStop("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止PHP-"+r.version+"失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php81Controller) Restart(ctx http.Context) http.Response { @@ -114,18 +89,11 @@ func (r *Php81Controller) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceRestart("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php81Controller) GetConfig(ctx http.Context) http.Response { @@ -193,7 +161,11 @@ func (r *Php81Controller) ErrorLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/php-fpm.log")) + log, err := tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/php-fpm.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -203,7 +175,11 @@ func (r *Php81Controller) SlowLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/slow.log")) + log, err := tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/slow.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -213,8 +189,11 @@ func (r *Php81Controller) ClearErrorLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/php-fpm.log") - return controllers.Success(ctx, true) + if out, err := tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/php-fpm.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + + return controllers.Success(ctx, nil) } func (r *Php81Controller) ClearSlowLog(ctx http.Context) http.Response { @@ -223,8 +202,10 @@ func (r *Php81Controller) ClearSlowLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/slow.log") - return controllers.Success(ctx, true) + if out, err := tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/slow.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } func (r *Php81Controller) GetExtensionList(ctx http.Context) http.Response { @@ -350,9 +331,12 @@ func (r *Php81Controller) GetExtensions() []PHPExtension { Installed: false, }) - raw := tools.Exec("/www/server/php/" + r.version + "/bin/php -m") - rawExtensionList := strings.Split(raw, "\n") + raw, err := tools.Exec("/www/server/php/" + r.version + "/bin/php -m") + if err != nil { + return extensions + } + rawExtensionList := strings.Split(raw, "\n") for _, item := range rawExtensionList { if !strings.Contains(item, "[") && item != "" { for i := range extensions { diff --git a/app/http/controllers/plugins/php82_controller.go b/app/http/controllers/plugins/php82_controller.go index 8f1d7d4892..b94d8ca3e0 100644 --- a/app/http/controllers/plugins/php82_controller.go +++ b/app/http/controllers/plugins/php82_controller.go @@ -36,16 +36,12 @@ func (r *Php82Controller) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("php-fpm-" + r.version) + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } func (r *Php82Controller) Reload(ctx http.Context) http.Response { @@ -54,18 +50,11 @@ func (r *Php82Controller) Reload(ctx http.Context) http.Response { return check } - tools.Exec("systemctl reload php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceReload("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php82Controller) Start(ctx http.Context) http.Response { @@ -74,18 +63,11 @@ func (r *Php82Controller) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceStart("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php82Controller) Stop(ctx http.Context) http.Response { @@ -94,18 +76,11 @@ func (r *Php82Controller) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceStop("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止PHP-"+r.version+"失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php82Controller) Restart(ctx http.Context) http.Response { @@ -114,18 +89,11 @@ func (r *Php82Controller) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart php-fpm-" + r.version) - out := tools.Exec("systemctl status php-fpm-" + r.version + " | grep Active | grep -v grep | awk '{print $2}'") - status := strings.TrimSpace(out) - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+r.version+"运行状态失败") + if err := tools.ServiceRestart("php-fpm-" + r.version); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启PHP-"+r.version+"失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } func (r *Php82Controller) GetConfig(ctx http.Context) http.Response { @@ -193,7 +161,11 @@ func (r *Php82Controller) ErrorLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/php-fpm.log")) + log, err := tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/php-fpm.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -203,7 +175,11 @@ func (r *Php82Controller) SlowLog(ctx http.Context) http.Response { return check } - log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/slow.log")) + log, err := tools.Exec("tail -n 100 /www/server/php/" + r.version + "/var/log/slow.log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -213,8 +189,11 @@ func (r *Php82Controller) ClearErrorLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/php-fpm.log") - return controllers.Success(ctx, true) + if out, err := tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/php-fpm.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + + return controllers.Success(ctx, nil) } func (r *Php82Controller) ClearSlowLog(ctx http.Context) http.Response { @@ -223,8 +202,10 @@ func (r *Php82Controller) ClearSlowLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/slow.log") - return controllers.Success(ctx, true) + if out, err := tools.Exec("echo '' > /www/server/php/" + r.version + "/var/log/slow.log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } func (r *Php82Controller) GetExtensionList(ctx http.Context) http.Response { @@ -344,9 +325,12 @@ func (r *Php82Controller) GetExtensions() []PHPExtension { Installed: false, }) - raw := tools.Exec("/www/server/php/" + r.version + "/bin/php -m") - rawExtensionList := strings.Split(raw, "\n") + raw, err := tools.Exec("/www/server/php/" + r.version + "/bin/php -m") + if err != nil { + return extensions + } + rawExtensionList := strings.Split(raw, "\n") for _, item := range rawExtensionList { if !strings.Contains(item, "[") && item != "" { for i := range extensions { diff --git a/app/http/controllers/plugins/phpmyadmin_controller.go b/app/http/controllers/plugins/phpmyadmin_controller.go index 5a1bfcf5e5..0be842133d 100644 --- a/app/http/controllers/plugins/phpmyadmin_controller.go +++ b/app/http/controllers/plugins/phpmyadmin_controller.go @@ -28,7 +28,7 @@ func (r *PhpMyAdminController) Info(ctx http.Context) http.Response { files, err := os.ReadDir("/www/server/phpmyadmin") if err != nil { - return controllers.Error(ctx, http.StatusUnprocessableEntity, "找不到 phpMyAdmin 目录") + return controllers.Error(ctx, http.StatusInternalServerError, "找不到 phpMyAdmin 目录") } var phpmyadmin string @@ -38,13 +38,13 @@ func (r *PhpMyAdminController) Info(ctx http.Context) http.Response { } } if len(phpmyadmin) == 0 { - return controllers.Error(ctx, http.StatusUnprocessableEntity, "找不到 phpMyAdmin 目录") + return controllers.Error(ctx, http.StatusInternalServerError, "找不到 phpMyAdmin 目录") } conf := tools.Read("/www/server/vhost/phpmyadmin.conf") match := regexp.MustCompile(`listen\s+(\d+);`).FindStringSubmatch(conf) if len(match) == 0 { - return controllers.Error(ctx, http.StatusUnprocessableEntity, "找不到 phpMyAdmin 端口") + return controllers.Error(ctx, http.StatusInternalServerError, "找不到 phpMyAdmin 端口") } return controllers.Success(ctx, http.Json{ @@ -61,7 +61,7 @@ func (r *PhpMyAdminController) SetPort(ctx http.Context) http.Response { port := ctx.Request().Input("port") if len(port) == 0 { - return controllers.Error(ctx, http.StatusUnprocessableEntity, "端口不能为空") + return controllers.Error(ctx, http.StatusInternalServerError, "端口不能为空") } conf := tools.Read("/www/server/vhost/phpmyadmin.conf") @@ -74,13 +74,25 @@ func (r *PhpMyAdminController) SetPort(ctx http.Context) http.Response { } if tools.IsRHEL() { - tools.Exec("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent") - tools.Exec("firewall-cmd --reload") + if out, err := tools.Exec("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("firewall-cmd --reload"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } } else { - tools.Exec("ufw allow " + port + "/tcp") - tools.Exec("ufw reload") + if out, err := tools.Exec("ufw allow " + port + "/tcp"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("ufw reload"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + } + + err := tools.ServiceReload("openresty") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载OpenResty失败") } - tools.Exec("systemctl reload openresty") return controllers.Success(ctx, nil) } diff --git a/app/http/controllers/plugins/postgresql15_controller.go b/app/http/controllers/plugins/postgresql15_controller.go index 7738051a12..19057a640b 100644 --- a/app/http/controllers/plugins/postgresql15_controller.go +++ b/app/http/controllers/plugins/postgresql15_controller.go @@ -4,7 +4,6 @@ import ( "strings" "github.com/goravel/framework/contracts/http" - "github.com/goravel/framework/facades" "github.com/goravel/framework/support/carbon" "panel/app/http/controllers" @@ -32,16 +31,12 @@ func (r *Postgresql15Controller) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("postgresql") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } // Reload 重载配置 @@ -51,17 +46,11 @@ func (r *Postgresql15Controller) Reload(ctx http.Context) http.Response { return check } - tools.Exec("systemctl reload postgresql") - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + if err := tools.ServiceReload("postgresql"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载PostgreSQL失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Restart 重启服务 @@ -71,17 +60,11 @@ func (r *Postgresql15Controller) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart postgresql") - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + if err := tools.ServiceRestart("postgresql"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启PostgreSQL失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Start 启动服务 @@ -91,17 +74,11 @@ func (r *Postgresql15Controller) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start postgresql") - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + if err := tools.ServiceStart("postgresql"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动PostgreSQL失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Stop 停止服务 @@ -111,17 +88,11 @@ func (r *Postgresql15Controller) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop postgresql") - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + if err := tools.ServiceStop("postgresql"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止PostgreSQL失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // GetConfig 获取配置 @@ -201,17 +172,41 @@ func (r *Postgresql15Controller) Load(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if status != "active" { - return controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL 已停止运行") + status, err := tools.ServiceStatus("postgresql") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + } + if !status { + return controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL已停止运行") + } + + time, err := tools.Exec(`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`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL进程PID失败") + } + process, err := tools.Exec(`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`) + 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`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL空间占用失败") } data := []LoadInfo{ - {"启动时间", carbon.Parse(tools.Exec(`echo "select pg_postmaster_start_time();" | su - postgres -c "psql" | sed -n 3p | cut -d'.' -f1`)).ToDateTimeString()}, - {"进程 PID", tools.Exec(`echo "select pg_backend_pid();" | su - postgres -c "psql" | sed -n 3p`)}, - {"进程数", tools.Exec(`ps aux | grep postgres | grep -v grep | wc -l`)}, - {"总连接数", tools.Exec(`echo "SELECT count(*) FROM pg_stat_activity WHERE NOT pid=pg_backend_pid();" | su - postgres -c "psql" | sed -n 3p`)}, - {"空间占用", tools.Exec(`echo "select pg_size_pretty(pg_database_size('postgres'));" | su - postgres -c "psql" | sed -n 3p`)}, + {"启动时间", carbon.Parse(time).ToDateTimeString()}, + {"进程 PID", pid}, + {"进程数", process}, + {"总连接数", connections}, + {"空间占用", storage}, } return controllers.Success(ctx, data) @@ -224,7 +219,11 @@ func (r *Postgresql15Controller) Log(ctx http.Context) http.Response { return check } - log := tools.Exec("tail -n 100 /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log") + log, err := tools.Exec("tail -n 100 /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -235,7 +234,10 @@ func (r *Postgresql15Controller) ClearLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log") + if out, err := tools.Exec("echo '' > /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } @@ -246,9 +248,12 @@ func (r *Postgresql15Controller) DatabaseList(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if status != "active" { - return controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL 已停止运行") + status, err := tools.ServiceStatus("postgresql") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + } + if !status { + return controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL已停止运行") } type database struct { @@ -257,7 +262,10 @@ func (r *Postgresql15Controller) DatabaseList(ctx http.Context) http.Response { Encoding string `json:"encoding"` } - raw := tools.Exec(`echo "\l" | su - postgres -c "psql"`) + raw, err := tools.Exec(`echo "\l" | su - postgres -c "psql"`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, raw) + } databases := strings.Split(raw, "\n") if len(databases) >= 4 { databases = databases[3 : len(databases)-1] @@ -326,13 +334,23 @@ func (r *Postgresql15Controller) AddDatabase(ctx http.Context) http.Response { user := ctx.Request().Input("user") password := ctx.Request().Input("password") - tools.Exec(`echo "CREATE DATABASE ` + database + `;" | su - postgres -c "psql"`) - tools.Exec(`echo "CREATE USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`) - tools.Exec(`echo "ALTER DATABASE ` + database + ` OWNER TO ` + user + `;" | su - postgres -c "psql"`) - tools.Exec(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`) + if out, err := tools.Exec(`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 { + 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 { + 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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } userConfig := "host " + database + " " + user + " 127.0.0.1/32 scram-sha-256" - tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`) + if out, err := tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return r.Reload(ctx) } @@ -355,7 +373,9 @@ func (r *Postgresql15Controller) DeleteDatabase(ctx http.Context) http.Response } database := ctx.Request().Input("database") - tools.Exec(`echo "DROP DATABASE ` + database + `;" | su - postgres -c "psql"`) + if out, err := tools.Exec(`echo "DROP DATABASE ` + database + `;" | su - postgres -c "psql"`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return controllers.Success(ctx, nil) } @@ -369,7 +389,6 @@ func (r *Postgresql15Controller) BackupList(ctx http.Context) http.Response { backupList, err := r.backup.PostgresqlList() if err != nil { - facades.Log().Info("[PostgreSQL] 获取备份列表失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取备份列表失败") } @@ -445,8 +464,7 @@ func (r *Postgresql15Controller) CreateBackup(ctx http.Context) http.Response { database := ctx.Request().Input("database") err = r.backup.PostgresqlBackup(database) if err != nil { - facades.Log().Info("[PostgreSQL] 创建备份失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "创建备份失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } return controllers.Success(ctx, nil) @@ -496,7 +514,6 @@ func (r *Postgresql15Controller) RestoreBackup(ctx http.Context) http.Response { err = r.backup.PostgresqlRestore(ctx.Request().Input("database"), ctx.Request().Input("backup")) if err != nil { - facades.Log().Info("[PostgreSQL] 还原失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "还原失败: "+err.Error()) } @@ -515,7 +532,10 @@ func (r *Postgresql15Controller) UserList(ctx http.Context) http.Response { Role string `json:"role"` } - raw := tools.Exec(`echo "\du" | su - postgres -c "psql"`) + raw, err := tools.Exec(`echo "\du" | su - postgres -c "psql"`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, raw) + } users := strings.Split(raw, "\n") if len(users) < 4 { return controllers.Error(ctx, http.StatusInternalServerError, "用户列表为空") @@ -578,11 +598,17 @@ func (r *Postgresql15Controller) AddUser(ctx http.Context) http.Response { user := ctx.Request().Input("user") password := ctx.Request().Input("password") database := ctx.Request().Input("database") - tools.Exec(`echo "CREATE USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`) - tools.Exec(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`) + if out, err := tools.Exec(`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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } userConfig := "host " + database + " " + user + " 127.0.0.1/32 scram-sha-256" - tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`) + if out, err := tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return r.Reload(ctx) } @@ -605,8 +631,12 @@ func (r *Postgresql15Controller) DeleteUser(ctx http.Context) http.Response { } user := ctx.Request().Input("user") - tools.Exec(`echo "DROP USER ` + user + `;" | su - postgres -c "psql"`) - tools.Exec(`sed -i '/` + user + `/d' /www/server/postgresql/data/pg_hba.conf`) + if out, err := tools.Exec(`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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return r.Reload(ctx) } @@ -631,7 +661,9 @@ func (r *Postgresql15Controller) SetUserPassword(ctx http.Context) http.Response user := ctx.Request().Input("user") password := ctx.Request().Input("password") - tools.Exec(`echo "ALTER USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`) + if out, err := tools.Exec(`echo "ALTER USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return controllers.Success(ctx, nil) } diff --git a/app/http/controllers/plugins/postgresql16_controller.go b/app/http/controllers/plugins/postgresql16_controller.go index a5810f9086..da523e1924 100644 --- a/app/http/controllers/plugins/postgresql16_controller.go +++ b/app/http/controllers/plugins/postgresql16_controller.go @@ -4,7 +4,6 @@ import ( "strings" "github.com/goravel/framework/contracts/http" - "github.com/goravel/framework/facades" "github.com/goravel/framework/support/carbon" "panel/app/http/controllers" @@ -32,16 +31,12 @@ func (r *Postgresql16Controller) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("postgresql") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } // Reload 重载配置 @@ -51,17 +46,11 @@ func (r *Postgresql16Controller) Reload(ctx http.Context) http.Response { return check } - tools.Exec("systemctl reload postgresql") - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + if err := tools.ServiceReload("postgresql"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载PostgreSQL失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Restart 重启服务 @@ -71,17 +60,11 @@ func (r *Postgresql16Controller) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart postgresql") - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + if err := tools.ServiceRestart("postgresql"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启PostgreSQL失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Start 启动服务 @@ -91,17 +74,11 @@ func (r *Postgresql16Controller) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start postgresql") - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + if err := tools.ServiceStart("postgresql"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动PostgreSQL失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Stop 停止服务 @@ -111,17 +88,11 @@ func (r *Postgresql16Controller) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop postgresql") - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + if err := tools.ServiceStop("postgresql"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止PostgreSQL失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // GetConfig 获取配置 @@ -201,17 +172,41 @@ func (r *Postgresql16Controller) Load(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if status != "active" { - return controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL 已停止运行") + status, err := tools.ServiceStatus("postgresql") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + } + if !status { + return controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL已停止运行") + } + + time, err := tools.Exec(`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`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL进程PID失败") + } + process, err := tools.Exec(`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`) + 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`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL空间占用失败") } data := []LoadInfo{ - {"启动时间", carbon.Parse(tools.Exec(`echo "select pg_postmaster_start_time();" | su - postgres -c "psql" | sed -n 3p | cut -d'.' -f1`)).ToDateTimeString()}, - {"进程 PID", tools.Exec(`echo "select pg_backend_pid();" | su - postgres -c "psql" | sed -n 3p`)}, - {"进程数", tools.Exec(`ps aux | grep postgres | grep -v grep | wc -l`)}, - {"总连接数", tools.Exec(`echo "SELECT count(*) FROM pg_stat_activity WHERE NOT pid=pg_backend_pid();" | su - postgres -c "psql" | sed -n 3p`)}, - {"空间占用", tools.Exec(`echo "select pg_size_pretty(pg_database_size('postgres'));" | su - postgres -c "psql" | sed -n 3p`)}, + {"启动时间", carbon.Parse(time).ToDateTimeString()}, + {"进程 PID", pid}, + {"进程数", process}, + {"总连接数", connections}, + {"空间占用", storage}, } return controllers.Success(ctx, data) @@ -224,7 +219,11 @@ func (r *Postgresql16Controller) Log(ctx http.Context) http.Response { return check } - log := tools.Exec("tail -n 100 /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log") + log, err := tools.Exec("tail -n 100 /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -235,7 +234,10 @@ func (r *Postgresql16Controller) ClearLog(ctx http.Context) http.Response { return check } - tools.Exec("echo '' > /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log") + if out, err := tools.Exec("echo '' > /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } @@ -246,9 +248,12 @@ func (r *Postgresql16Controller) DatabaseList(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") - if status != "active" { - return controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL 已停止运行") + status, err := tools.ServiceStatus("postgresql") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + } + if !status { + return controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL已停止运行") } type database struct { @@ -257,7 +262,10 @@ func (r *Postgresql16Controller) DatabaseList(ctx http.Context) http.Response { Encoding string `json:"encoding"` } - raw := tools.Exec(`echo "\l" | su - postgres -c "psql"`) + raw, err := tools.Exec(`echo "\l" | su - postgres -c "psql"`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, raw) + } databases := strings.Split(raw, "\n") if len(databases) >= 4 { databases = databases[3 : len(databases)-1] @@ -326,13 +334,23 @@ func (r *Postgresql16Controller) AddDatabase(ctx http.Context) http.Response { user := ctx.Request().Input("user") password := ctx.Request().Input("password") - tools.Exec(`echo "CREATE DATABASE ` + database + `;" | su - postgres -c "psql"`) - tools.Exec(`echo "CREATE USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`) - tools.Exec(`echo "ALTER DATABASE ` + database + ` OWNER TO ` + user + `;" | su - postgres -c "psql"`) - tools.Exec(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`) + if out, err := tools.Exec(`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 { + 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 { + 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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } userConfig := "host " + database + " " + user + " 127.0.0.1/32 scram-sha-256" - tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`) + if out, err := tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return r.Reload(ctx) } @@ -355,7 +373,9 @@ func (r *Postgresql16Controller) DeleteDatabase(ctx http.Context) http.Response } database := ctx.Request().Input("database") - tools.Exec(`echo "DROP DATABASE ` + database + `;" | su - postgres -c "psql"`) + if out, err := tools.Exec(`echo "DROP DATABASE ` + database + `;" | su - postgres -c "psql"`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return controllers.Success(ctx, nil) } @@ -369,7 +389,6 @@ func (r *Postgresql16Controller) BackupList(ctx http.Context) http.Response { backupList, err := r.backup.PostgresqlList() if err != nil { - facades.Log().Info("[PostgreSQL] 获取备份列表失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取备份列表失败") } @@ -445,8 +464,7 @@ func (r *Postgresql16Controller) CreateBackup(ctx http.Context) http.Response { database := ctx.Request().Input("database") err = r.backup.PostgresqlBackup(database) if err != nil { - facades.Log().Info("[PostgreSQL] 创建备份失败:" + err.Error()) - return controllers.Error(ctx, http.StatusInternalServerError, "创建备份失败") + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } return controllers.Success(ctx, nil) @@ -496,7 +514,6 @@ func (r *Postgresql16Controller) RestoreBackup(ctx http.Context) http.Response { err = r.backup.PostgresqlRestore(ctx.Request().Input("database"), ctx.Request().Input("backup")) if err != nil { - facades.Log().Info("[PostgreSQL] 还原失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "还原失败: "+err.Error()) } @@ -515,7 +532,10 @@ func (r *Postgresql16Controller) UserList(ctx http.Context) http.Response { Role string `json:"role"` } - raw := tools.Exec(`echo "\du" | su - postgres -c "psql"`) + raw, err := tools.Exec(`echo "\du" | su - postgres -c "psql"`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, raw) + } users := strings.Split(raw, "\n") if len(users) < 4 { return controllers.Error(ctx, http.StatusInternalServerError, "用户列表为空") @@ -578,11 +598,17 @@ func (r *Postgresql16Controller) AddUser(ctx http.Context) http.Response { user := ctx.Request().Input("user") password := ctx.Request().Input("password") database := ctx.Request().Input("database") - tools.Exec(`echo "CREATE USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`) - tools.Exec(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`) + if out, err := tools.Exec(`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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } userConfig := "host " + database + " " + user + " 127.0.0.1/32 scram-sha-256" - tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`) + if out, err := tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return r.Reload(ctx) } @@ -605,8 +631,12 @@ func (r *Postgresql16Controller) DeleteUser(ctx http.Context) http.Response { } user := ctx.Request().Input("user") - tools.Exec(`echo "DROP USER ` + user + `;" | su - postgres -c "psql"`) - tools.Exec(`sed -i '/` + user + `/d' /www/server/postgresql/data/pg_hba.conf`) + if out, err := tools.Exec(`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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return r.Reload(ctx) } @@ -631,7 +661,9 @@ func (r *Postgresql16Controller) SetUserPassword(ctx http.Context) http.Response user := ctx.Request().Input("user") password := ctx.Request().Input("password") - tools.Exec(`echo "ALTER USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`) + if out, err := tools.Exec(`echo "ALTER USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return controllers.Success(ctx, nil) } diff --git a/app/http/controllers/plugins/pureftpd_controller.go b/app/http/controllers/plugins/pureftpd_controller.go index 999d77ed33..8583b76f30 100644 --- a/app/http/controllers/plugins/pureftpd_controller.go +++ b/app/http/controllers/plugins/pureftpd_controller.go @@ -30,16 +30,12 @@ func (r *PureFtpdController) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("pure-ftpd") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } // Restart 重启服务 @@ -49,17 +45,12 @@ func (r *PureFtpdController) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart pure-ftpd") - status := tools.Exec("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd状态失败") + err := tools.ServiceRestart("pure-ftpd") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启PureFtpd失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Start 启动服务 @@ -69,17 +60,12 @@ func (r *PureFtpdController) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start pure-ftpd") - status := tools.Exec("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd状态失败") + err := tools.ServiceStart("pure-ftpd") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动PureFtpd失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Stop 停止服务 @@ -89,17 +75,12 @@ func (r *PureFtpdController) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop pure-ftpd") - status := tools.Exec("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd状态失败") + err := tools.ServiceStop("pure-ftpd") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止PureFtpd失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // List 获取用户列表 @@ -109,8 +90,8 @@ func (r *PureFtpdController) List(ctx http.Context) http.Response { return check } - listRaw := tools.Exec("pure-pw list") - if len(listRaw) == 0 { + listRaw, err := tools.Exec("pure-pw list") + if err != nil { return controllers.Success(ctx, http.Json{ "total": 0, "items": []User{}, @@ -188,8 +169,12 @@ func (r *PureFtpdController) Add(ctx http.Context) http.Response { if err = tools.Chown(path, "www", "www"); err != nil { return nil } - tools.Exec(`yes '` + password + `' | pure-pw useradd ` + username + ` -u www -g www -d ` + path) - tools.Exec("pure-pw mkdb") + if out, err := tools.Exec(`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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return controllers.Success(ctx, nil) } @@ -213,8 +198,12 @@ func (r *PureFtpdController) Delete(ctx http.Context) http.Response { username := ctx.Request().Input("username") - tools.Exec("pure-pw userdel " + username + " -m") - tools.Exec("pure-pw mkdb") + if out, err := tools.Exec("pure-pw userdel " + username + " -m"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("pure-pw mkdb"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return controllers.Success(ctx, nil) } @@ -240,8 +229,12 @@ func (r *PureFtpdController) ChangePassword(ctx http.Context) http.Response { username := ctx.Request().Input("username") password := ctx.Request().Input("password") - tools.Exec(`yes '` + password + `' | pure-pw passwd ` + username + ` -m`) - tools.Exec("pure-pw mkdb") + if out, err := tools.Exec(`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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return controllers.Success(ctx, nil) } @@ -253,8 +246,8 @@ func (r *PureFtpdController) GetPort(ctx http.Context) http.Response { return check } - port := tools.Exec(`cat /www/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`) - if len(port) == 0 { + port, err := tools.Exec(`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端口失败") } @@ -279,15 +272,24 @@ func (r *PureFtpdController) SetPort(ctx http.Context) http.Response { } port := ctx.Request().Input("port") - tools.Exec(`sed -i "s/Bind.*/Bind 0.0.0.0,` + port + `/g" /www/server/pure-ftpd/etc/pure-ftpd.conf`) + 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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } if tools.IsRHEL() { - tools.Exec("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent") - tools.Exec("firewall-cmd --reload") + if out, err := tools.Exec("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("firewall-cmd --reload"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } } else { - tools.Exec("ufw allow " + port + "/tcp") - tools.Exec("ufw reload") + if out, err := tools.Exec("ufw allow " + port + "/tcp"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("ufw reload"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } } - tools.Exec("systemctl restart pure-ftpd") - return controllers.Success(ctx, nil) + return r.Restart(ctx) } diff --git a/app/http/controllers/plugins/redis_controller.go b/app/http/controllers/plugins/redis_controller.go index 196facd51f..2b6c0cd922 100644 --- a/app/http/controllers/plugins/redis_controller.go +++ b/app/http/controllers/plugins/redis_controller.go @@ -23,16 +23,12 @@ func (r *RedisController) Status(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { + status, err := tools.ServiceStatus("redis") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, status) } // Restart 重启服务 @@ -42,17 +38,11 @@ func (r *RedisController) Restart(ctx http.Context) http.Response { return check } - tools.Exec("systemctl restart redis") - status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败") + if err := tools.ServiceRestart("redis"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启Redis失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Start 启动服务 @@ -62,17 +52,11 @@ func (r *RedisController) Start(ctx http.Context) http.Response { return check } - tools.Exec("systemctl start redis") - status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败") + if err := tools.ServiceStart("redis"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动Redis失败") } - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // Stop 停止服务 @@ -82,17 +66,11 @@ func (r *RedisController) Stop(ctx http.Context) http.Response { return check } - tools.Exec("systemctl stop redis") - status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'") - if len(status) == 0 { - return controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败") + if err := tools.ServiceStop("redis"); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止Redis失败") } - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) - } + return controllers.Success(ctx, nil) } // GetConfig 获取配置 @@ -137,13 +115,16 @@ func (r *RedisController) Load(ctx http.Context) http.Response { return check } - status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'") - if status != "active" { - return controllers.Error(ctx, http.StatusInternalServerError, "Redis 已停止运行") + status, err := tools.ServiceStatus("redis") + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败") + } + if !status { + return controllers.Error(ctx, http.StatusInternalServerError, "Redis已停止运行") } - raw := tools.Exec("redis-cli info") - if len(raw) == 0 { + raw, err := tools.Exec("redis-cli info") + if err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "获取Redis负载失败") } diff --git a/app/http/controllers/plugins/s3fs_controller.go b/app/http/controllers/plugins/s3fs_controller.go index a74f2f1092..b4d14e4e14 100644 --- a/app/http/controllers/plugins/s3fs_controller.go +++ b/app/http/controllers/plugins/s3fs_controller.go @@ -36,7 +36,7 @@ func (r *S3fsController) List(ctx http.Context) http.Response { var s3fsList []S3fsMount err := json.UnmarshalString(r.setting.Get("s3fs", "[]"), &s3fsList) if err != nil { - return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取 S3fs 挂载失败") + return controllers.Error(ctx, http.StatusInternalServerError, "获取 S3fs 挂载失败") } startIndex := (page - 1) * limit @@ -120,15 +120,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 } - 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`) - mountCheck := tools.Exec("mount -a 2>&1") - if len(mountCheck) != 0 { - tools.Exec(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`) + 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`) + 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`) return controllers.Error(ctx, http.StatusInternalServerError, "检测到/etc/fstab有误: "+mountCheck) } - dfCheck := tools.Exec("df -h | grep " + path + " 2>&1") - if len(dfCheck) == 0 { - tools.Exec(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`) + if _, err := tools.Exec("df -h | grep " + path + " 2>&1"); err != nil { + _, _ = tools.Exec(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`) return controllers.Error(ctx, http.StatusInternalServerError, "挂载失败,请检查配置是否正确") } @@ -179,11 +180,16 @@ func (r *S3fsController) Delete(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "挂载ID不存在") } - tools.Exec(`fusermount -u '` + mount.Path + `' 2>&1`) - tools.Exec(`umount '` + mount.Path + `' 2>&1`) - tools.Exec(`sed -i 's@^s3fs#` + mount.Bucket + `\s` + mount.Path + `.*$@@g' /etc/fstab`) - mountCheck := tools.Exec("mount -a 2>&1") - if len(mountCheck) != 0 { + if out, err := tools.Exec(`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 { + 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 { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if mountCheck, err := tools.Exec("mount -a 2>&1"); err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "检测到/etc/fstab有误: "+mountCheck) } tools.Remove("/etc/passwd-s3fs-" + cast.ToString(mount.ID)) diff --git a/app/http/controllers/plugins/supervisor_controller.go b/app/http/controllers/plugins/supervisor_controller.go index 04ce9d8049..2e6dc0357d 100644 --- a/app/http/controllers/plugins/supervisor_controller.go +++ b/app/http/controllers/plugins/supervisor_controller.go @@ -34,12 +34,12 @@ func (r *SupervisorController) Status(ctx http.Context) http.Response { return check } - status := tools.Exec(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`) - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) + status, err := tools.ServiceStatus(r.ServiceName) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "获取Supervisor状态失败") } + + return controllers.Success(ctx, status) } // Start 启动 @@ -49,13 +49,11 @@ func (r *SupervisorController) Start(ctx http.Context) http.Response { return check } - tools.Exec(`systemctl start ` + r.ServiceName) - status := tools.Exec(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`) - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) + if err := tools.ServiceStart(r.ServiceName); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "启动Supervisor失败") } + + return controllers.Success(ctx, nil) } // Stop 停止 @@ -65,13 +63,11 @@ func (r *SupervisorController) Stop(ctx http.Context) http.Response { return check } - tools.Exec(`systemctl stop ` + r.ServiceName) - status := tools.Exec(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`) - if status != "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) + if err := tools.ServiceStop(r.ServiceName); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "停止Supervisor失败") } + + return controllers.Success(ctx, nil) } // Restart 重启 @@ -81,13 +77,11 @@ func (r *SupervisorController) Restart(ctx http.Context) http.Response { return check } - tools.Exec(`systemctl restart ` + r.ServiceName) - status := tools.Exec(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`) - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) + if err := tools.ServiceRestart(r.ServiceName); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重启Supervisor失败") } + + return controllers.Success(ctx, nil) } // Reload 重载 @@ -97,13 +91,11 @@ func (r *SupervisorController) Reload(ctx http.Context) http.Response { return check } - tools.Exec(`systemctl reload ` + r.ServiceName) - status := tools.Exec(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`) - if status == "active" { - return controllers.Success(ctx, true) - } else { - return controllers.Success(ctx, false) + if err := tools.ServiceReload(r.ServiceName); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "重载Supervisor失败") } + + return controllers.Success(ctx, nil) } // Log 日志 @@ -113,7 +105,11 @@ func (r *SupervisorController) Log(ctx http.Context) http.Response { return check } - log := tools.Exec(`tail -n 200 /var/log/supervisor/supervisord.log`) + log, err := tools.Exec(`tail -n 200 /var/log/supervisor/supervisord.log`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) + } + return controllers.Success(ctx, log) } @@ -124,7 +120,10 @@ func (r *SupervisorController) ClearLog(ctx http.Context) http.Response { return check } - tools.Exec(`echo "" > /var/log/supervisor/supervisord.log`) + if out, err := tools.Exec(`echo "" > /var/log/supervisor/supervisord.log`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } @@ -141,6 +140,7 @@ func (r *SupervisorController) Config(ctx http.Context) http.Response { } else { config = tools.Read(`/etc/supervisor/supervisord.conf`) } + return controllers.Success(ctx, config) } @@ -160,7 +160,7 @@ func (r *SupervisorController) SaveConfig(ctx http.Context) http.Response { } if err != nil { - return controllers.Error(ctx, http.StatusUnprocessableEntity, err.Error()) + return controllers.Error(ctx, http.StatusInternalServerError, err.Error()) } return r.Restart(ctx) @@ -183,7 +183,11 @@ func (r *SupervisorController) Processes(ctx http.Context) http.Response { Uptime string `json:"uptime"` } - out := tools.Exec(`supervisorctl status | awk '{print $1}'`) + out, err := tools.Exec(`supervisorctl status | awk '{print $1}'`) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + var processList []process for _, line := range strings.Split(out, "\n") { if len(line) == 0 { @@ -192,10 +196,14 @@ func (r *SupervisorController) Processes(ctx http.Context) http.Response { var p process p.Name = line - p.Status = tools.Exec(`supervisorctl status ` + line + ` | awk '{print $2}'`) + if status, err := tools.Exec(`supervisorctl status ` + line + ` | awk '{print $2}'`); err == nil { + p.Status = status + } if p.Status == "RUNNING" { - p.Pid = strings.ReplaceAll(tools.Exec(`supervisorctl status `+line+` | awk '{print $4}'`), ",", "") - p.Uptime = tools.Exec(`supervisorctl status ` + line + ` | awk '{print $6}'`) + pid, _ := tools.Exec(`supervisorctl status ` + line + ` | awk '{print $4}'`) + p.Pid = strings.ReplaceAll(pid, ",", "") + uptime, _ := tools.Exec(`supervisorctl status ` + line + ` | awk '{print $6}'`) + p.Uptime = uptime } else { p.Pid = "-" p.Uptime = "-" @@ -233,7 +241,10 @@ func (r *SupervisorController) StartProcess(ctx http.Context) http.Response { } process := ctx.Request().Input("process") - tools.Exec(`supervisorctl start ` + process) + if out, err := tools.Exec(`supervisorctl start ` + process); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } @@ -245,7 +256,10 @@ func (r *SupervisorController) StopProcess(ctx http.Context) http.Response { } process := ctx.Request().Input("process") - tools.Exec(`supervisorctl stop ` + process) + if out, err := tools.Exec(`supervisorctl stop ` + process); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } @@ -257,7 +271,10 @@ func (r *SupervisorController) RestartProcess(ctx http.Context) http.Response { } process := ctx.Request().Input("process") - tools.Exec(`supervisorctl restart ` + process) + if out, err := tools.Exec(`supervisorctl restart ` + process); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + return controllers.Success(ctx, nil) } @@ -270,13 +287,22 @@ func (r *SupervisorController) ProcessLog(ctx http.Context) http.Response { process := ctx.Request().Input("process") var logPath string + var err error if tools.IsRHEL() { - logPath = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) + logPath, err = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) } else { - logPath = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) + logPath, err = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) + } + + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "无法从进程"+process+"的配置文件中获取日志路径") + } + + log, err := tools.Exec(`tail -n 200 ` + logPath) + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, log) } - log := tools.Exec(`tail -n 200 ` + logPath) return controllers.Success(ctx, log) } @@ -289,13 +315,21 @@ func (r *SupervisorController) ClearProcessLog(ctx http.Context) http.Response { process := ctx.Request().Input("process") var logPath string + var err error if tools.IsRHEL() { - logPath = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) + logPath, err = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) } else { - logPath = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) + logPath, err = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) + } + + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "无法从进程"+process+"的配置文件中获取日志路径") + } + + if out, err := tools.Exec(`echo "" > ` + logPath); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) } - tools.Exec(`echo "" > ` + logPath) return controllers.Success(ctx, nil) } @@ -337,9 +371,15 @@ 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 start ` + process) + if out, err := tools.Exec(`supervisorctl reread`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec(`supervisorctl update`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec(`supervisorctl start ` + process); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return controllers.Success(ctx, nil) } @@ -392,9 +432,15 @@ 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) + if out, err := tools.Exec(`supervisorctl reread`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec(`supervisorctl update`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec(`supervisorctl start ` + name); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return controllers.Success(ctx, nil) } @@ -407,18 +453,31 @@ func (r *SupervisorController) DeleteProcess(ctx http.Context) http.Response { } process := ctx.Request().Input("process") - tools.Exec(`supervisorctl stop ` + process) + if out, err := tools.Exec(`supervisorctl stop ` + process); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + var logPath string + var err error if tools.IsRHEL() { - logPath = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) + logPath, err = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) tools.Remove(`/etc/supervisord.d/` + process + `.conf`) } else { - logPath = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) + logPath, err = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`) tools.Remove(`/etc/supervisor/conf.d/` + process + `.conf`) } + + if err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, "无法从进程"+process+"的配置文件中获取日志路径") + } + tools.Remove(logPath) - tools.Exec(`supervisorctl reread`) - tools.Exec(`supervisorctl update`) + if out, err := tools.Exec(`supervisorctl reread`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec(`supervisorctl update`); err != nil { + return controllers.Error(ctx, http.StatusInternalServerError, out) + } return controllers.Success(ctx, nil) } diff --git a/app/http/controllers/plugins/toolbox_controller.go b/app/http/controllers/plugins/toolbox_controller.go index 5977b951ec..927cf2195a 100644 --- a/app/http/controllers/plugins/toolbox_controller.go +++ b/app/http/controllers/plugins/toolbox_controller.go @@ -28,7 +28,7 @@ func (r *ToolBoxController) GetDNS(ctx http.Context) http.Response { raw := tools.Read("/etc/resolv.conf") match := regexp.MustCompile(`nameserver\s+(\S+)`).FindAllStringSubmatch(raw, -1) if len(match) == 0 { - return controllers.Error(ctx, http.StatusUnprocessableEntity, "找不到 DNS 信息") + return controllers.Error(ctx, http.StatusInternalServerError, "找不到 DNS 信息") } var dns []string @@ -58,7 +58,7 @@ func (r *ToolBoxController) SetDNS(ctx http.Context) http.Response { dns += "nameserver " + dns2 + "\n" if err := tools.Write("/etc/resolv.conf", dns, 0644); err != nil { - return controllers.Error(ctx, http.StatusUnprocessableEntity, "写入 DNS 信息失败") + return controllers.Error(ctx, http.StatusInternalServerError, "写入 DNS 信息失败") } return controllers.Success(ctx, nil) @@ -86,7 +86,11 @@ func (r *ToolBoxController) GetSWAP(ctx http.Context) http.Response { total = "0.00 B" } - raw := tools.Exec("LC_ALL=C free | grep Swap") + raw, err := tools.Exec("free | grep Swap") + if err != nil { + return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取 SWAP 信息失败") + } + match := regexp.MustCompile(`Swap:\s+(\d+)\s+(\d+)\s+(\d+)`).FindStringSubmatch(raw) if len(match) > 0 { used = tools.FormatBytes(cast.ToFloat64(match[2]) * 1024) @@ -111,28 +115,48 @@ func (r *ToolBoxController) SetSWAP(ctx http.Context) http.Response { size := ctx.Request().InputInt("size") if tools.Exists("/www/swap") { - tools.Exec("swapoff /www/swap") - tools.Exec("rm -f /www/swap") - tools.Exec("sed -i '/www\\/swap/d' /etc/fstab") + if out, err := tools.Exec("swapoff /www/swap"); err != nil { + return controllers.Error(ctx, http.StatusUnprocessableEntity, out) + } + if out, err := tools.Exec("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 { + return controllers.Error(ctx, http.StatusUnprocessableEntity, out) + } } if size > 1 { - free := tools.Exec("df -k /www | awk '{print $4}' | tail -n 1") + free, err := tools.Exec("df -k /www | awk '{print $4}' | tail -n 1") + if err != nil { + return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取磁盘空间失败") + } if cast.ToInt64(free)*1024 < int64(size)*1024*1024 { return controllers.Error(ctx, http.StatusUnprocessableEntity, "磁盘空间不足,当前剩余 "+tools.FormatBytes(cast.ToFloat64(free))) } - if strings.Contains(tools.Exec("df -T /www | awk '{print $2}' | tail -n 1"), "btrfs") { - tools.Exec("btrfs filesystem mkswapfile --size " + cast.ToString(size) + "M --uuid clear /www/swap") + btrfsCheck, _ := tools.Exec("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 { + return controllers.Error(ctx, http.StatusUnprocessableEntity, out) + } } else { - tools.Exec("dd if=/dev/zero of=/www/swap bs=1M count=" + cast.ToString(size)) - tools.Exec("mkswap -f /www/swap") + if out, err := tools.Exec("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 { + return controllers.Error(ctx, http.StatusUnprocessableEntity, out) + } if err := tools.Chmod("/www/swap", 0600); err != nil { return controllers.Error(ctx, http.StatusUnprocessableEntity, "设置 SWAP 权限失败") } } - tools.Exec("swapon /www/swap") - tools.Exec("echo '/www/swap swap swap defaults 0 0' >> /etc/fstab") + if out, err := tools.Exec("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 { + return controllers.Error(ctx, http.StatusUnprocessableEntity, out) + } } return controllers.Success(ctx, nil) @@ -145,7 +169,11 @@ func (r *ToolBoxController) GetTimezone(ctx http.Context) http.Response { return check } - raw := tools.Exec("LC_ALL=C timedatectl | grep zone") + raw, err := tools.Exec("timedatectl | grep zone") + if err != nil { + return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取时区信息失败") + } + match := regexp.MustCompile(`zone:\s+(\S+)`).FindStringSubmatch(raw) if len(match) == 0 { return controllers.Error(ctx, http.StatusUnprocessableEntity, "找不到时区信息") @@ -156,7 +184,10 @@ func (r *ToolBoxController) GetTimezone(ctx http.Context) http.Response { Value string `json:"value"` } - zonesRaw := tools.Exec("LC_ALL=C timedatectl list-timezones") + zonesRaw, err := tools.Exec("timedatectl list-timezones") + if err != nil { + return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取时区列表失败") + } zones := strings.Split(zonesRaw, "\n") var zonesList []zone diff --git a/app/http/controllers/safe_controller.go b/app/http/controllers/safe_controller.go index 9cb1416b06..6c0fc45462 100644 --- a/app/http/controllers/safe_controller.go +++ b/app/http/controllers/safe_controller.go @@ -6,6 +6,7 @@ import ( "github.com/goravel/framework/contracts/http" "github.com/spf13/cast" + commonrequests "panel/app/http/requests/common" "panel/pkg/tools" ) @@ -28,33 +29,47 @@ func (r *SafeController) GetFirewallStatus(ctx http.Context) http.Response { // SetFirewallStatus 设置防火墙状态 func (r *SafeController) SetFirewallStatus(ctx http.Context) http.Response { var out string + var err error if ctx.Request().InputBool("status") { if tools.IsRHEL() { - out = tools.Exec("systemctl start firewalld") + out, err = tools.Exec("systemctl start firewalld") } else { - out = tools.Exec("echo y | ufw enable") + out, err = tools.Exec("echo y | ufw enable") } } else { if tools.IsRHEL() { - out = tools.Exec("systemctl stop firewalld") + out, err = tools.Exec("systemctl stop firewalld") } else { - out = tools.Exec("ufw disable") + out, err = tools.Exec("ufw disable") } } - return Success(ctx, out) + if err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + + return Success(ctx, nil) } // GetFirewallRules 获取防火墙规则 func (r *SafeController) GetFirewallRules(ctx http.Context) http.Response { + var paginateRequest commonrequests.Paginate + sanitize := Sanitize(ctx, &paginateRequest) + if sanitize != nil { + return sanitize + } + if !r.firewallStatus() { return Success(ctx, nil) } - page := ctx.Request().QueryInt("page", 1) - limit := ctx.Request().QueryInt("limit", 10) + var rules []map[string]string if tools.IsRHEL() { - out := tools.Exec("firewall-cmd --list-all 2>&1") + out, err := tools.Exec("firewall-cmd --list-all 2>&1") + if err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + match := regexp.MustCompile(`ports: (.*)`).FindStringSubmatch(out) if len(match) == 0 { return Success(ctx, http.Json{ @@ -63,7 +78,6 @@ func (r *SafeController) GetFirewallRules(ctx http.Context) http.Response { }) } ports := strings.Split(match[1], " ") - var rules []map[string]string for _, port := range ports { rule := strings.Split(port, "/") rules = append(rules, map[string]string{ @@ -71,33 +85,18 @@ func (r *SafeController) GetFirewallRules(ctx http.Context) http.Response { "protocol": rule[1], }) } - - startIndex := (page - 1) * limit - endIndex := page * limit - if startIndex > len(rules) { - return Success(ctx, http.Json{ - "total": 0, - "items": []map[string]string{}, - }) - } - if endIndex > len(rules) { - endIndex = len(rules) + } else { + out, err := tools.Exec("ufw status | grep -v '(v6)' | grep ALLOW | awk '{print $1}'") + if err != nil { + return Error(ctx, http.StatusInternalServerError, out) } - pagedRules := rules[startIndex:endIndex] - return Success(ctx, http.Json{ - "total": len(rules), - "items": pagedRules, - }) - } else { - out := tools.Exec("ufw status | grep -v '(v6)' | grep ALLOW | awk '{print $1}'") if len(out) == 0 { return Success(ctx, http.Json{ "total": 0, "items": []map[string]string{}, }) } - var rules []map[string]string for _, port := range strings.Split(out, "\n") { rule := strings.Split(port, "/") rules = append(rules, map[string]string{ @@ -105,31 +104,31 @@ func (r *SafeController) GetFirewallRules(ctx http.Context) http.Response { "protocol": rule[1], }) } + } - startIndex := (page - 1) * limit - endIndex := page * limit - if startIndex > len(rules) { - return Success(ctx, http.Json{ - "total": 0, - "items": []map[string]string{}, - }) - } - if endIndex > len(rules) { - endIndex = len(rules) - } - pagedRules := rules[startIndex:endIndex] - + startIndex := (paginateRequest.Page - 1) * paginateRequest.Limit + endIndex := paginateRequest.Page * paginateRequest.Limit + if startIndex > len(rules) { return Success(ctx, http.Json{ - "total": len(rules), - "items": pagedRules, + "total": 0, + "items": []map[string]string{}, }) } + if endIndex > len(rules) { + endIndex = len(rules) + } + pagedRules := rules[startIndex:endIndex] + + return Success(ctx, http.Json{ + "total": len(rules), + "items": pagedRules, + }) } // AddFirewallRule 添加防火墙规则 func (r *SafeController) AddFirewallRule(ctx http.Context) http.Response { if !r.firewallStatus() { - return Error(ctx, http.StatusUnprocessableEntity, "防火墙未启动") + return Error(ctx, http.StatusInternalServerError, "防火墙未启动") } port := ctx.Request().Input("port") @@ -153,17 +152,29 @@ func (r *SafeController) AddFirewallRule(ctx http.Context) http.Response { } if tools.IsRHEL() { - tools.Exec("firewall-cmd --remove-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1") - tools.Exec("firewall-cmd --add-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1") - tools.Exec("firewall-cmd --reload") + if out, err := tools.Exec("firewall-cmd --remove-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1"); 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 { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("firewall-cmd --reload"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } else { // ufw 需要替换 - 为 : 添加 if strings.Contains(port, "-") { port = strings.ReplaceAll(port, "-", ":") } - tools.Exec("ufw delete allow " + cast.ToString(port) + "/" + protocol) - tools.Exec("ufw allow " + cast.ToString(port) + "/" + protocol) - tools.Exec("ufw reload") + if out, err := tools.Exec("ufw delete allow " + cast.ToString(port) + "/" + protocol); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("ufw allow " + cast.ToString(port) + "/" + protocol); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("ufw reload"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } return Success(ctx, nil) @@ -182,11 +193,19 @@ func (r *SafeController) DeleteFirewallRule(ctx http.Context) http.Response { } if tools.IsRHEL() { - tools.Exec("firewall-cmd --remove-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1") - tools.Exec("firewall-cmd --reload") + if out, err := tools.Exec("firewall-cmd --remove-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("firewall-cmd --reload"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } else { - tools.Exec("ufw delete allow " + cast.ToString(port) + "/" + protocol) - tools.Exec("ufw reload") + if out, err := tools.Exec("ufw delete allow " + cast.ToString(port) + "/" + protocol); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("ufw reload"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } return Success(ctx, nil) @@ -195,16 +214,17 @@ func (r *SafeController) DeleteFirewallRule(ctx http.Context) http.Response { // firewallStatus 获取防火墙状态 func (r *SafeController) firewallStatus() bool { var out string + var err error var running bool if tools.IsRHEL() { - out = tools.Exec("systemctl status firewalld | grep Active | awk '{print $3}'") + out, err = tools.Exec("systemctl status firewalld | grep Active | awk '{print $3}'") if out == "(running)" { running = true } else { running = false } } else { - out = tools.Exec("ufw status | grep Status | awk '{print $2}'") + out, err = tools.Exec("ufw status | grep Status | awk '{print $2}'") if out == "active" { running = true } else { @@ -212,43 +232,63 @@ func (r *SafeController) firewallStatus() bool { } } + if err != nil { + return false + } + return running } // GetSshStatus 获取 SSH 状态 func (r *SafeController) GetSshStatus(ctx http.Context) http.Response { var out string + var err error if tools.IsRHEL() { - out = tools.Exec("systemctl status sshd | grep Active | awk '{print $3}'") + out, err = tools.Exec("systemctl status sshd | grep Active | awk '{print $3}'") } else { - out = tools.Exec("systemctl status ssh | grep Active | awk '{print $3}'") + out, err = tools.Exec("systemctl status ssh | grep Active | awk '{print $3}'") } - running := false - if out == "(running)" { - running = true + if err != nil { + return Error(ctx, http.StatusInternalServerError, out) } - return Success(ctx, running) + return Success(ctx, out == "(running)") } // SetSshStatus 设置 SSH 状态 func (r *SafeController) SetSshStatus(ctx http.Context) http.Response { if ctx.Request().InputBool("status") { if tools.IsRHEL() { - tools.Exec("systemctl enable sshd") - tools.Exec("systemctl start sshd") + if out, err := tools.Exec("systemctl enable sshd"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("systemctl start sshd"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } else { - tools.Exec("systemctl enable ssh") - tools.Exec("systemctl start ssh") + if out, err := tools.Exec("systemctl enable ssh"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("systemctl start ssh"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } } else { if tools.IsRHEL() { - tools.Exec("systemctl stop sshd") - tools.Exec("systemctl disable sshd") + if out, err := tools.Exec("systemctl stop sshd"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("systemctl disable sshd"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } else { - tools.Exec("systemctl stop ssh") - tools.Exec("systemctl disable ssh") + if out, err := tools.Exec("systemctl stop ssh"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("systemctl disable ssh"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } } @@ -257,7 +297,11 @@ func (r *SafeController) SetSshStatus(ctx http.Context) http.Response { // GetSshPort 获取 SSH 端口 func (r *SafeController) GetSshPort(ctx http.Context) http.Response { - out := tools.Exec("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'") + out, err := tools.Exec("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'") + if err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + return Success(ctx, out) } @@ -268,21 +312,30 @@ func (r *SafeController) SetSshPort(ctx http.Context) http.Response { return Error(ctx, http.StatusUnprocessableEntity, "参数错误") } - oldPort := tools.Exec("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'") - 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") + oldPort, err := tools.Exec("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") - if status := tools.Exec("systemctl status sshd | grep Active | awk '{print $3}'"); status == "(running)" { - tools.Exec("systemctl restart sshd") + out, err := tools.Exec("systemctl status sshd | grep Active | awk '{print $3}'") + if err != nil || out != "(running)" { + Error(ctx, http.StatusInternalServerError, out) } + _, _ = tools.Exec("systemctl restart sshd") return Success(ctx, nil) } // GetPingStatus 获取 Ping 状态 func (r *SafeController) GetPingStatus(ctx http.Context) http.Response { if tools.IsRHEL() { - out := tools.Exec(`firewall-cmd --list-all 2>&1`) + out, err := tools.Exec(`firewall-cmd --list-all 2>&1`) + if err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if !strings.Contains(out, `rule protocol value="icmp" drop`) { return Success(ctx, true) } else { @@ -300,20 +353,34 @@ func (r *SafeController) GetPingStatus(ctx http.Context) http.Response { // SetPingStatus 设置 Ping 状态 func (r *SafeController) SetPingStatus(ctx http.Context) http.Response { + var out string + var err error if tools.IsRHEL() { if ctx.Request().InputBool("status") { - tools.Exec(`firewall-cmd --permanent --remove-rich-rule='rule protocol value=icmp drop'`) + out, err = tools.Exec(`firewall-cmd --permanent --remove-rich-rule='rule protocol value=icmp drop'`) } else { - tools.Exec(`firewall-cmd --permanent --add-rich-rule='rule protocol value=icmp drop'`) + out, err = tools.Exec(`firewall-cmd --permanent --add-rich-rule='rule protocol value=icmp drop'`) } - tools.Exec(`firewall-cmd --reload`) } else { if ctx.Request().InputBool("status") { - 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 = 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`) } else { - 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 = 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`) } - tools.Exec(`ufw reload`) + } + + if err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + + if tools.IsRHEL() { + out, err = tools.Exec(`firewall-cmd --reload`) + } else { + out, err = tools.Exec(`ufw reload`) + } + + if err != nil { + return Error(ctx, http.StatusInternalServerError, out) } return Success(ctx, nil) diff --git a/app/http/controllers/setting_controller.go b/app/http/controllers/setting_controller.go index ff63fcc5d9..1c75764d78 100644 --- a/app/http/controllers/setting_controller.go +++ b/app/http/controllers/setting_controller.go @@ -35,7 +35,9 @@ func (r *SettingController) List(ctx http.Context) http.Response { var settings []models.Setting err := facades.Orm().Query().Get(&settings) if err != nil { - facades.Log().Info("[面板][SettingController] 查询设置列表失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{ + "error": err.Error(), + }).Info("获取面板设置列表失败") return ErrorSystem(ctx) } @@ -48,13 +50,21 @@ func (r *SettingController) List(ctx http.Context) http.Response { var user models.User err = facades.Auth().User(ctx, &user) if err != nil { - facades.Log().Info("[面板][SettingController] 获取用户失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{ + "error": err.Error(), + }).Info("获取用户信息失败") return ErrorSystem(ctx) } result.Username = user.Username result.Email = user.Email - result.Port = tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`) + result.Port, err = tools.Exec(`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(), + }).Info("获取面板端口失败") + return ErrorSystem(ctx) + } return Success(ctx, result) } @@ -79,9 +89,9 @@ func (r *SettingController) Update(ctx http.Context) http.Response { err := r.setting.Set(models.SettingKeyName, updateRequest.Name) if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{ "error": err.Error(), - }).Tags("面板", "面板设置").Info("保存面板名称失败") + }).Info("保存面板名称失败") return ErrorSystem(ctx) } @@ -92,9 +102,9 @@ func (r *SettingController) Update(ctx http.Context) http.Response { } err = r.setting.Set(models.SettingKeyBackupPath, updateRequest.BackupPath) if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{ "error": err.Error(), - }).Tags("面板", "面板设置").Info("保存备份目录失败") + }).Info("保存备份目录失败") return ErrorSystem(ctx) } if !tools.Exists(updateRequest.WebsitePath) { @@ -107,9 +117,9 @@ func (r *SettingController) Update(ctx http.Context) http.Response { } err = r.setting.Set(models.SettingKeyWebsitePath, updateRequest.WebsitePath) if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{ "error": err.Error(), - }).Tags("面板", "面板设置").Info("保存建站目录失败") + }).Info("保存建站目录失败") return ErrorSystem(ctx) } @@ -128,30 +138,61 @@ func (r *SettingController) Update(ctx http.Context) http.Response { user.Password = hash } if err = facades.Orm().Query().Save(&user); err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "面板设置").With(map[string]any{ "error": err.Error(), - }).Tags("面板", "面板设置").Info("保存用户信息失败") + }).Info("保存用户信息失败") + return ErrorSystem(ctx) + } + + oldPort, err := tools.Exec(`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(), + }).Info("获取面板端口失败") return ErrorSystem(ctx) } - oldPort := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`) port := cast.ToString(updateRequest.Port) if oldPort != port { - tools.Exec("sed -i 's/APP_PORT=" + oldPort + "/APP_PORT=" + port + "/g' /www/panel/panel.conf") + if out, err := tools.Exec("sed -i 's/APP_PORT=" + oldPort + "/APP_PORT=" + port + "/g' /www/panel/panel.conf"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } if tools.IsRHEL() { - tools.Exec("firewall-cmd --remove-port=" + cast.ToString(port) + "/tcp --permanent 2>&1") - tools.Exec("firewall-cmd --add-port=" + cast.ToString(port) + "/tcp --permanent 2>&1") - tools.Exec("firewall-cmd --reload") + if out, err := tools.Exec("firewall-cmd --remove-port=" + cast.ToString(port) + "/tcp --permanent 2>&1"); 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 { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("firewall-cmd --reload"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } else { - tools.Exec("ufw delete allow " + cast.ToString(port) + "/tcp") - tools.Exec("ufw allow " + cast.ToString(port) + "/tcp") - tools.Exec("ufw reload") + if out, err := tools.Exec("ufw delete allow " + cast.ToString(port) + "/tcp"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("ufw allow " + cast.ToString(port) + "/tcp"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } + if out, err := tools.Exec("ufw reload"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } } - oldEntrance := tools.Exec(`cat /www/panel/panel.conf | grep APP_ENTRANCE | awk -F '=' '{print $2}' | tr -d '\n'`) + + oldEntrance, err := tools.Exec(`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(), + }).Info("获取面板入口失败") + return ErrorSystem(ctx) + } + entrance := cast.ToString(updateRequest.Entrance) if oldEntrance != entrance { - tools.Exec("sed -i 's!APP_ENTRANCE=" + oldEntrance + "!APP_ENTRANCE=" + entrance + "!g' /www/panel/panel.conf") + if out, err := tools.Exec("sed -i 's!APP_ENTRANCE=" + oldEntrance + "!APP_ENTRANCE=" + entrance + "!g' /www/panel/panel.conf"); err != nil { + return Error(ctx, http.StatusInternalServerError, out) + } } if oldPort != port || oldEntrance != entrance { diff --git a/app/http/controllers/ssh_controller.go b/app/http/controllers/ssh_controller.go index 3bb8de9144..1108336f4a 100644 --- a/app/http/controllers/ssh_controller.go +++ b/app/http/controllers/ssh_controller.go @@ -67,25 +67,17 @@ func (r *SshController) UpdateInfo(ctx http.Context) http.Response { port := ctx.Request().Input("port") user := ctx.Request().Input("user") password := ctx.Request().Input("password") - err = r.setting.Set(models.SettingKeySshHost, host) - if err != nil { - facades.Log().Info("[面板][SSH] 更新配置失败 ", err) - return ErrorSystem(ctx) + if err = r.setting.Set(models.SettingKeySshHost, host); err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) } - err = r.setting.Set(models.SettingKeySshPort, port) - if err != nil { - facades.Log().Info("[面板][SSH] 更新配置失败 ", err) - return ErrorSystem(ctx) + if err = r.setting.Set(models.SettingKeySshPort, port); err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) } - err = r.setting.Set(models.SettingKeySshUser, user) - if err != nil { - facades.Log().Info("[面板][SSH] 更新配置失败 ", err) - return ErrorSystem(ctx) + if err = r.setting.Set(models.SettingKeySshUser, user); err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) } - err = r.setting.Set(models.SettingKeySshPassword, password) - if err != nil { - facades.Log().Info("[面板][SSH] 更新配置失败 ", err) - return ErrorSystem(ctx) + if err = r.setting.Set(models.SettingKeySshPassword, password); err != nil { + return Error(ctx, http.StatusInternalServerError, err.Error()) } return Success(ctx, nil) @@ -142,21 +134,24 @@ func (r *SshController) Session(ctx http.Context) http.Response { defer wg.Done() err := turn.LoopRead(logBuff, ctx2) if err != nil { - facades.Log().Info("[面板][SSH] 读取数据失败 ", err.Error()) + facades.Log().Request(ctx.Request()).Tags("面板", "SSH").With(map[string]any{ + "error": err.Error(), + }).Info("SSH 会话错误") } }() go func() { defer wg.Done() err := turn.SessionWait() if err != nil { - facades.Log().Info("[面板][SSH] 会话失败 ", err.Error()) + facades.Log().Request(ctx.Request()).Tags("面板", "SSH").With(map[string]any{ + "error": err.Error(), + }).Info("SSH 会话错误") } cancel() }() wg.Wait() }) if err != nil { - facades.Log().Info("[面板][SSH] 建立连接失败 ", err) return ErrorSystem(ctx) } diff --git a/app/http/controllers/task_controller.go b/app/http/controllers/task_controller.go index 7b37da5258..f609967735 100644 --- a/app/http/controllers/task_controller.go +++ b/app/http/controllers/task_controller.go @@ -38,9 +38,9 @@ func (r *TaskController) List(ctx http.Context) http.Response { var total int64 err := facades.Orm().Query().Order("id desc").Paginate(ctx.Request().QueryInt("page", 1), ctx.Request().QueryInt("limit", 10), &tasks, &total) if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "任务中心").With(map[string]any{ "error": err.Error(), - }).Info("[面板][TaskController] 查询任务列表失败") + }).Info("查询任务列表失败") return ErrorSystem(ctx) } @@ -55,14 +55,17 @@ func (r *TaskController) Log(ctx http.Context) http.Response { var task models.Task err := facades.Orm().Query().Where("id", ctx.Request().QueryInt("id")).FirstOrFail(&task) if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "任务中心").With(map[string]any{ "id": ctx.Request().QueryInt("id"), "error": err.Error(), - }).Info("[面板][TaskController] 查询任务失败") + }).Info("查询任务失败") return ErrorSystem(ctx) } - log := tools.Exec("tail -n 1000 " + task.Log) + log, err := tools.Exec("tail -n 1000 " + task.Log) + if err != nil { + return Error(ctx, http.StatusInternalServerError, log) + } return Success(ctx, log) } @@ -72,10 +75,10 @@ func (r *TaskController) Delete(ctx http.Context) http.Response { var task models.Task _, err := facades.Orm().Query().Where("id", ctx.Request().Input("id")).Delete(&task) if err != nil { - facades.Log().With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "任务中心").With(map[string]any{ "id": ctx.Request().QueryInt("id"), "error": err.Error(), - }).Info("[面板][TaskController] 删除任务失败") + }).Info("删除任务失败") return ErrorSystem(ctx) } diff --git a/app/http/controllers/user_controller.go b/app/http/controllers/user_controller.go index 615872da83..e9c1599c0c 100644 --- a/app/http/controllers/user_controller.go +++ b/app/http/controllers/user_controller.go @@ -41,9 +41,9 @@ func (r *UserController) Login(ctx http.Context) http.Response { var user models.User err := facades.Orm().Query().Where("username", loginRequest.Username).First(&user) if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "用户").With(map[string]any{ "error": err.Error(), - }).Tags("面板", "用户").Info("查询用户失败") + }).Info("查询用户失败") return ErrorSystem(ctx) } @@ -54,18 +54,18 @@ func (r *UserController) Login(ctx http.Context) http.Response { if facades.Hash().NeedsRehash(user.Password) { user.Password, err = facades.Hash().Make(loginRequest.Password) if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "用户").With(map[string]any{ "error": err.Error(), - }).Tags("面板", "用户").Info("更新密码失败") + }).Info("更新密码失败") return ErrorSystem(ctx) } } token, loginErr := facades.Auth().LoginUsingID(ctx, user.ID) if loginErr != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "用户").With(map[string]any{ "error": err.Error(), - }).Tags("面板", "用户").Info("登录失败") + }).Info("登录失败") return ErrorSystem(ctx) } @@ -87,9 +87,9 @@ func (r *UserController) Info(ctx http.Context) http.Response { var user models.User err := facades.Auth().User(ctx, &user) if err != nil { - facades.Log().Request(ctx.Request()).With(map[string]any{ + facades.Log().Request(ctx.Request()).Tags("面板", "用户").With(map[string]any{ "error": err.Error(), - }).Tags("面板", "用户").Info("获取用户信息失败") + }).Info("获取用户信息失败") return ErrorSystem(ctx) } diff --git a/app/http/controllers/website_controller.go b/app/http/controllers/website_controller.go index 80a9868e3e..0c2feb16cc 100644 --- a/app/http/controllers/website_controller.go +++ b/app/http/controllers/website_controller.go @@ -40,14 +40,14 @@ func NewWebsiteController() *WebsiteController { // @Param data body commonrequests.Paginate true "request" // @Success 200 {object} SuccessResponse{data=responses.List} // @Router /panel/website [get] -func (c *WebsiteController) List(ctx http.Context) http.Response { +func (r *WebsiteController) List(ctx http.Context) http.Response { var paginateRequest commonrequests.Paginate sanitize := Sanitize(ctx, &paginateRequest) if sanitize != nil { return sanitize } - total, websites, err := c.website.List(paginateRequest.Page, paginateRequest.Limit) + total, websites, err := r.website.List(paginateRequest.Page, paginateRequest.Limit) if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ "error": err.Error(), @@ -72,7 +72,7 @@ func (c *WebsiteController) List(ctx http.Context) http.Response { // @Param data body requests.Add true "request" // @Success 200 {object} SuccessResponse // @Router /panel/website [post] -func (c *WebsiteController) Add(ctx http.Context) http.Response { +func (r *WebsiteController) Add(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check @@ -83,11 +83,18 @@ func (c *WebsiteController) Add(ctx http.Context) http.Response { return sanitize } + if len(addRequest.Path) == 0 { + addRequest.Path = r.setting.Get(models.SettingKeyWebsitePath) + "/" + addRequest.Name + } + website := services.PanelWebsite{ Name: addRequest.Name, + Status: true, Domains: addRequest.Domains, Ports: addRequest.Ports, + Path: addRequest.Path, Php: addRequest.Php, + Ssl: false, Db: addRequest.Db, DbType: addRequest.DbType, DbName: addRequest.DbName, @@ -95,7 +102,7 @@ func (c *WebsiteController) Add(ctx http.Context) http.Response { DbPassword: addRequest.DbPassword, } - _, err := c.website.Add(website) + _, err := r.website.Add(website) if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ "error": err.Error(), @@ -117,7 +124,7 @@ func (c *WebsiteController) Add(ctx http.Context) http.Response { // @Param id path int true "网站 ID" // @Success 200 {object} SuccessResponse // @Router /panel/website/{id} [delete] -func (c *WebsiteController) Delete(ctx http.Context) http.Response { +func (r *WebsiteController) Delete(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check @@ -129,7 +136,7 @@ func (c *WebsiteController) Delete(ctx http.Context) http.Response { return sanitize } - err := c.website.Delete(idRequest.ID) + err := r.website.Delete(idRequest.ID) if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ "id": idRequest.ID, @@ -150,7 +157,7 @@ func (c *WebsiteController) Delete(ctx http.Context) http.Response { // @Security BearerToken // @Success 200 {object} SuccessResponse{data=map[string]string} // @Router /panel/website/defaultConfig [get] -func (c *WebsiteController) GetDefaultConfig(ctx http.Context) http.Response { +func (r *WebsiteController) GetDefaultConfig(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check @@ -175,7 +182,7 @@ func (c *WebsiteController) GetDefaultConfig(ctx http.Context) http.Response { // @Param data body map[string]string true "request" // @Success 200 {object} SuccessResponse // @Router /panel/website/defaultConfig [post] -func (c *WebsiteController) SaveDefaultConfig(ctx http.Context) http.Response { +func (r *WebsiteController) SaveDefaultConfig(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check @@ -211,7 +218,7 @@ func (c *WebsiteController) SaveDefaultConfig(ctx http.Context) http.Response { // @Param id path int true "网站 ID" // @Success 200 {object} SuccessResponse{data=services.PanelWebsite} // @Router /panel/website/config/{id} [get] -func (c *WebsiteController) GetConfig(ctx http.Context) http.Response { +func (r *WebsiteController) GetConfig(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check @@ -223,7 +230,7 @@ func (c *WebsiteController) GetConfig(ctx http.Context) http.Response { return sanitize } - config, err := c.website.GetConfig(idRequest.ID) + config, err := r.website.GetConfig(idRequest.ID) if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ "id": idRequest.ID, @@ -247,7 +254,7 @@ func (c *WebsiteController) GetConfig(ctx http.Context) http.Response { // @Param data body requests.SaveConfig true "request" // @Success 200 {object} SuccessResponse // @Router /panel/website/config/{id} [post] -func (c *WebsiteController) SaveConfig(ctx http.Context) http.Response { +func (r *WebsiteController) SaveConfig(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check @@ -259,7 +266,7 @@ func (c *WebsiteController) SaveConfig(ctx http.Context) http.Response { return sanitize } - err := c.website.SaveConfig(saveConfigRequest) + err := r.website.SaveConfig(saveConfigRequest) if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ "error": err.Error(), @@ -281,7 +288,7 @@ func (c *WebsiteController) SaveConfig(ctx http.Context) http.Response { // @Param id path int true "网站 ID" // @Success 200 {object} SuccessResponse // @Router /panel/website/log/{id} [delete] -func (c *WebsiteController) ClearLog(ctx http.Context) http.Response { +func (r *WebsiteController) ClearLog(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check @@ -314,7 +321,7 @@ func (c *WebsiteController) ClearLog(ctx http.Context) http.Response { // @Param id path int true "网站 ID" // @Success 200 {object} SuccessResponse // @Router /panel/website/updateRemark/{id} [post] -func (c *WebsiteController) UpdateRemark(ctx http.Context) http.Response { +func (r *WebsiteController) UpdateRemark(ctx http.Context) http.Response { var idRequest requests.ID sanitize := Sanitize(ctx, &idRequest) if sanitize != nil { @@ -348,8 +355,8 @@ func (c *WebsiteController) UpdateRemark(ctx http.Context) http.Response { // @Security BearerToken // @Success 200 {object} SuccessResponse{data=[]services.BackupFile} // @Router /panel/website/backupList [get] -func (c *WebsiteController) BackupList(ctx http.Context) http.Response { - backupList, err := c.backup.WebsiteList() +func (r *WebsiteController) BackupList(ctx http.Context) http.Response { + backupList, err := r.backup.WebsiteList() if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ "error": err.Error(), @@ -371,7 +378,7 @@ func (c *WebsiteController) BackupList(ctx http.Context) http.Response { // @Param data body requests.ID true "request" // @Success 200 {object} SuccessResponse // @Router /panel/website/createBackup [post] -func (c *WebsiteController) CreateBackup(ctx http.Context) http.Response { +func (r *WebsiteController) CreateBackup(ctx http.Context) http.Response { var idRequest requests.ID sanitize := Sanitize(ctx, &idRequest) if sanitize != nil { @@ -387,7 +394,7 @@ func (c *WebsiteController) CreateBackup(ctx http.Context) http.Response { return ErrorSystem(ctx) } - if err := c.backup.WebSiteBackup(website); err != nil { + if err := r.backup.WebSiteBackup(website); err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ "id": idRequest.ID, "error": err.Error(), @@ -409,13 +416,13 @@ func (c *WebsiteController) CreateBackup(ctx http.Context) http.Response { // @Param file formData file true "备份文件" // @Success 200 {object} SuccessResponse // @Router /panel/website/uploadBackup [post] -func (c *WebsiteController) UploadBackup(ctx http.Context) http.Response { +func (r *WebsiteController) UploadBackup(ctx http.Context) http.Response { file, err := ctx.Request().File("file") if err != nil { - return Error(ctx, http.StatusUnprocessableEntity, "上传文件失败") + return Error(ctx, http.StatusInternalServerError, "上传文件失败") } - backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/website" + backupPath := r.setting.Get(models.SettingKeyBackupPath) + "/website" if !tools.Exists(backupPath) { if err = tools.Mkdir(backupPath, 0644); err != nil { return nil @@ -445,7 +452,7 @@ func (c *WebsiteController) UploadBackup(ctx http.Context) http.Response { // @Param data body requests.RestoreBackup true "request" // @Success 200 {object} SuccessResponse // @Router /panel/website/restoreBackup [post] -func (c *WebsiteController) RestoreBackup(ctx http.Context) http.Response { +func (r *WebsiteController) RestoreBackup(ctx http.Context) http.Response { var restoreBackupRequest requests.RestoreBackup sanitize := Sanitize(ctx, &restoreBackupRequest) if sanitize != nil { @@ -457,7 +464,7 @@ func (c *WebsiteController) RestoreBackup(ctx http.Context) http.Response { return ErrorSystem(ctx) } - if err := c.backup.WebsiteRestore(website, restoreBackupRequest.Name); err != nil { + if err := r.backup.WebsiteRestore(website, restoreBackupRequest.Name); err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ "id": restoreBackupRequest.ID, "file": restoreBackupRequest.Name, @@ -480,14 +487,14 @@ func (c *WebsiteController) RestoreBackup(ctx http.Context) http.Response { // @Param data body requests.DeleteBackup true "request" // @Success 200 {object} SuccessResponse // @Router /panel/website/deleteBackup [delete] -func (c *WebsiteController) DeleteBackup(ctx http.Context) http.Response { +func (r *WebsiteController) DeleteBackup(ctx http.Context) http.Response { var deleteBackupRequest requests.DeleteBackup sanitize := Sanitize(ctx, &deleteBackupRequest) if sanitize != nil { return sanitize } - backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/website" + backupPath := r.setting.Get(models.SettingKeyBackupPath) + "/website" if !tools.Exists(backupPath) { if err := tools.Mkdir(backupPath, 0644); err != nil { return nil @@ -512,7 +519,7 @@ func (c *WebsiteController) DeleteBackup(ctx http.Context) http.Response { // @Param data body requests.ID true "request" // @Success 200 {object} SuccessResponse // @Router /panel/website/resetConfig [post] -func (c *WebsiteController) ResetConfig(ctx http.Context) http.Response { +func (r *WebsiteController) ResetConfig(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check @@ -603,7 +610,9 @@ server if err := tools.Write("/www/server/vhost/rewrite"+website.Name+".conf", "", 0644); err != nil { return nil } - tools.Exec("systemctl reload openresty") + if exec, err := tools.Exec("systemctl reload openresty"); err != nil { + return Error(ctx, http.StatusInternalServerError, exec) + } return Success(ctx, nil) } @@ -619,7 +628,7 @@ server // @Param id path int true "网站 ID" // @Success 200 {object} SuccessResponse // @Router /panel/website/status/{id} [post] -func (c *WebsiteController) Status(ctx http.Context) http.Response { +func (r *WebsiteController) Status(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check @@ -672,7 +681,9 @@ func (c *WebsiteController) Status(ctx http.Context) http.Response { if err := tools.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644); err != nil { return ErrorSystem(ctx) } - tools.Exec("systemctl reload openresty") + if exec, err := tools.Exec("systemctl reload openresty"); err != nil { + return Error(ctx, http.StatusInternalServerError, exec) + } return Success(ctx, nil) } diff --git a/app/http/requests/website/add.go b/app/http/requests/website/add.go index 0ec9bfc1e2..a7c679b14b 100644 --- a/app/http/requests/website/add.go +++ b/app/http/requests/website/add.go @@ -9,6 +9,7 @@ type Add struct { Name string `form:"name" json:"name"` Domains []string `form:"domains" json:"domains"` Ports []string `form:"ports" json:"ports"` + Path string `form:"path" json:"path"` Php int `form:"php" json:"php"` Db bool `form:"db" json:"db"` DbType string `form:"db_type" json:"db_type"` @@ -23,9 +24,10 @@ func (r *Add) Authorize(ctx http.Context) error { func (r *Add) Rules(ctx http.Context) map[string]string { return map[string]string{ - "name": "required|regex:^[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)*$|not_exists:websites,name", + "name": "required|regex:^[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)*$|not_exists:websites,name|not_in:phpmyadmin,mysql,panel,ssh", "domains": "required|slice", "ports": "required|slice", + "path": "regex:^/[a-zA-Z0-9_-]+(\\/[a-zA-Z0-9_-]+)*$", "php": "required", "db": "bool", "db_type": "required_if:db,true|in:mysql,postgresql", diff --git a/app/services/backup.go b/app/services/backup.go index a283d74bc1..f87dc6dd40 100644 --- a/app/services/backup.go +++ b/app/services/backup.go @@ -88,7 +88,9 @@ func (s *BackupImpl) WebSiteBackup(website models.Website) error { } backupFile := backupPath + "/" + website.Name + "_" + carbon.Now().ToShortDateTimeString() + ".zip" - tools.Exec(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`) + if _, err := tools.Exec(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`); err != nil { + return err + } return nil } @@ -112,8 +114,12 @@ func (s *BackupImpl) WebsiteRestore(website models.Website, backupFile string) e return errors.New("备份文件不存在") } - tools.Exec(`rm -rf '` + website.Path + `/*'`) - tools.Exec(`unzip -o '` + backupFile + `' -d '` + website.Path + `' 2>&1`) + if _, err := tools.Exec(`rm -rf '` + website.Path + `/*'`); err != nil { + return err + } + if _, err := tools.Exec(`unzip -o '` + backupFile + `' -d '` + website.Path + `' 2>&1`); err != nil { + return err + } if err := tools.Chmod(website.Path, 0755); err != nil { return err } @@ -172,12 +178,15 @@ func (s *BackupImpl) MysqlBackup(database string) error { return err } - tools.Exec("/www/server/mysql/bin/mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile) - tools.Exec("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile) + if _, err := tools.Exec("/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 { + return err + } tools.Remove(backupPath + "/" + backupFile) - _ = os.Unsetenv("MYSQL_PWD") - return nil + return os.Unsetenv("MYSQL_PWD") } // MysqlRestore MySQL恢复 @@ -197,26 +206,38 @@ func (s *BackupImpl) MysqlRestore(database string, backupFile string) error { switch ext { case ".zip": - tools.Exec("unzip -o " + backupFile + " -d " + backupPath) + if _, err := tools.Exec("unzip -o " + backupFile + " -d " + backupPath); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ext) case ".gz": if strings.HasSuffix(backupFile, ".tar.gz") { // 解压.tar.gz文件 - tools.Exec("tar -zxvf " + backupFile + " -C " + backupPath) + if _, err := tools.Exec("tar -zxvf " + backupFile + " -C " + backupPath); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ".tar.gz") } else { // 解压.gz文件 - tools.Exec("gzip -d " + backupFile) + if _, err := tools.Exec("gzip -d " + backupFile); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ext) } case ".bz2": - tools.Exec("bzip2 -d " + backupFile) + if _, err := tools.Exec("bzip2 -d " + backupFile); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ext) case ".tar": - tools.Exec("tar -xvf " + backupFile + " -C " + backupPath) + if _, err := tools.Exec("tar -xvf " + backupFile + " -C " + backupPath); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ext) case ".rar": - tools.Exec("unrar x " + backupFile + " " + backupPath) + if _, err := tools.Exec("unrar x " + backupFile + " " + backupPath); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ext) } @@ -224,10 +245,11 @@ func (s *BackupImpl) MysqlRestore(database string, backupFile string) error { return errors.New("自动解压失败,请手动解压") } - tools.Exec("/www/server/mysql/bin/mysql -uroot " + database + " < " + backupFile) - _ = os.Unsetenv("MYSQL_PWD") + if _, err := tools.Exec("/www/server/mysql/bin/mysql -uroot " + database + " < " + backupFile); err != nil { + return err + } - return nil + return os.Unsetenv("MYSQL_PWD") } // PostgresqlList PostgreSQL备份列表 @@ -273,10 +295,14 @@ func (s *BackupImpl) PostgresqlBackup(database string) error { } } - tools.Exec(`su - postgres -c "pg_dump ` + database + `" > ` + backupPath + "/" + backupFile) - tools.Exec("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile) - tools.Remove(backupPath + "/" + backupFile) + if _, err := tools.Exec(`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 { + return err + } + tools.Remove(backupPath + "/" + backupFile) return nil } @@ -291,26 +317,38 @@ func (s *BackupImpl) PostgresqlRestore(database string, backupFile string) error switch ext { case ".zip": - tools.Exec("unzip -o " + backupFile + " -d " + backupPath) + if _, err := tools.Exec("unzip -o " + backupFile + " -d " + backupPath); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ext) case ".gz": if strings.HasSuffix(backupFile, ".tar.gz") { // 解压.tar.gz文件 - tools.Exec("tar -zxvf " + backupFile + " -C " + backupPath) + if _, err := tools.Exec("tar -zxvf " + backupFile + " -C " + backupPath); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ".tar.gz") } else { // 解压.gz文件 - tools.Exec("gzip -d " + backupFile) + if _, err := tools.Exec("gzip -d " + backupFile); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ext) } case ".bz2": - tools.Exec("bzip2 -d " + backupFile) + if _, err := tools.Exec("bzip2 -d " + backupFile); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ext) case ".tar": - tools.Exec("tar -xvf " + backupFile + " -C " + backupPath) + if _, err := tools.Exec("tar -xvf " + backupFile + " -C " + backupPath); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ext) case ".rar": - tools.Exec("unrar x " + backupFile + " " + backupPath) + if _, err := tools.Exec("unrar x " + backupFile + " " + backupPath); err != nil { + return err + } backupFile = strings.TrimSuffix(backupFile, ext) } @@ -318,7 +356,9 @@ func (s *BackupImpl) PostgresqlRestore(database string, backupFile string) error return errors.New("自动解压失败,请手动解压") } - tools.Exec(`su - postgres -c "psql ` + database + `" < ` + backupFile) + if _, err := tools.Exec(`su - postgres -c "psql ` + database + `" < ` + backupFile); err != nil { + return err + } return nil } diff --git a/app/services/cert.go b/app/services/cert.go index 46fcd90bae..b4ea142cf3 100644 --- a/app/services/cert.go +++ b/app/services/cert.go @@ -316,7 +316,9 @@ func (s *CertImpl) ObtainAuto(ID uint) (certificate.Resource, error) { if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".key", string(ssl.PrivateKey), 0644); err != nil { return certificate.Resource{}, err } - tools.Exec("systemctl reload openresty") + if _, err := tools.Exec("systemctl reload openresty"); err != nil { + return certificate.Resource{}, err + } } return ssl, nil @@ -374,7 +376,9 @@ func (s *CertImpl) ObtainManual(ID uint) (certificate.Resource, error) { if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".key", string(ssl.PrivateKey), 0644); err != nil { return certificate.Resource{}, err } - tools.Exec("systemctl reload openresty") + if _, err := tools.Exec("systemctl reload openresty"); err != nil { + return certificate.Resource{}, err + } } return ssl, nil @@ -479,7 +483,9 @@ func (s *CertImpl) Renew(ID uint) (certificate.Resource, error) { if err := tools.Write("/www/server/vhost/ssl/"+cert.Website.Name+".key", string(ssl.PrivateKey), 0644); err != nil { return certificate.Resource{}, err } - tools.Exec("systemctl reload openresty") + if _, err := tools.Exec("systemctl reload openresty"); err != nil { + return certificate.Resource{}, err + } } return ssl, nil diff --git a/app/services/cron.go b/app/services/cron.go index 49bf509523..c510896fa5 100644 --- a/app/services/cron.go +++ b/app/services/cron.go @@ -8,8 +8,8 @@ import ( ) type Cron interface { - AddToSystem(cron models.Cron) - DeleteFromSystem(cron models.Cron) + AddToSystem(cron models.Cron) error + DeleteFromSystem(cron models.Cron) error } type CronImpl struct { @@ -20,25 +20,45 @@ func NewCronImpl() *CronImpl { } // AddToSystem 添加到系统 -func (r *CronImpl) AddToSystem(cron models.Cron) { +func (r *CronImpl) AddToSystem(cron models.Cron) error { if tools.IsRHEL() { - tools.Exec("echo \"" + cron.Time + " " + cron.Shell + " >> " + cron.Log + " 2>&1\" >> /var/spool/cron/root") - tools.Exec("systemctl restart crond") + if _, err := tools.Exec("echo \"" + cron.Time + " " + cron.Shell + " >> " + cron.Log + " 2>&1\" >> /var/spool/cron/root"); err != nil { + return err + } + if _, err := tools.Exec("systemctl restart crond"); err != nil { + return err + } } else { - tools.Exec("echo \"" + cron.Time + " " + cron.Shell + " >> " + cron.Log + " 2>&1\" >> /var/spool/cron/crontabs/root") - tools.Exec("systemctl restart cron") + if _, err := tools.Exec("echo \"" + cron.Time + " " + cron.Shell + " >> " + cron.Log + " 2>&1\" >> /var/spool/cron/crontabs/root"); err != nil { + return err + } + if _, err := tools.Exec("systemctl restart cron"); err != nil { + return err + } } + + return nil } // DeleteFromSystem 从系统中删除 -func (r *CronImpl) DeleteFromSystem(cron models.Cron) { +func (r *CronImpl) DeleteFromSystem(cron models.Cron) error { // 需要转义Shell路径的/为\/ cron.Shell = strings.ReplaceAll(cron.Shell, "/", "\\/") if tools.IsRHEL() { - tools.Exec("sed -i '/" + cron.Shell + "/d' /var/spool/cron/root") - tools.Exec("systemctl restart crond") + if _, err := tools.Exec("sed -i '/" + cron.Shell + "/d' /var/spool/cron/root"); err != nil { + return err + } + if _, err := tools.Exec("systemctl restart crond"); err != nil { + return err + } } else { - tools.Exec("sed -i '/" + cron.Shell + "/d' /var/spool/cron/crontabs/root") - tools.Exec("systemctl restart cron") + if _, err := tools.Exec("sed -i '/" + cron.Shell + "/d' /var/spool/cron/crontabs/root"); err != nil { + return err + } + if _, err := tools.Exec("systemctl restart cron"); err != nil { + return err + } } + + return nil } diff --git a/app/services/website.go b/app/services/website.go index 486afea34e..0b5f3764d7 100644 --- a/app/services/website.go +++ b/app/services/website.go @@ -11,7 +11,6 @@ import ( "strings" "github.com/goravel/framework/facades" - "golang.org/x/exp/slices" requests "panel/app/http/requests/website" "panel/app/models" @@ -95,24 +94,6 @@ func (r *WebsiteImpl) List(page, limit int) (int64, []models.Website, error) { // Add 添加网站 func (r *WebsiteImpl) Add(website PanelWebsite) (models.Website, error) { - // 禁止部分保留名称 - nameSlices := []string{"phpmyadmin", "mysql", "panel", "ssh"} - if slices.Contains(nameSlices, website.Name) { - return models.Website{}, errors.New("网站名称" + website.Name + "为保留名称,请更换") - } - - // path为空时,设置默认值 - if len(website.Path) == 0 { - website.Path = r.setting.Get(models.SettingKeyWebsitePath) + "/" + website.Name - } - // path不为/开头时,返回错误 - if website.Path[0] != '/' { - return models.Website{}, errors.New("网站路径" + website.Path + "必须以/开头") - } - - website.Ssl = false - website.Status = true - w := models.Website{ Name: website.Name, Status: website.Status, @@ -295,20 +276,38 @@ server return models.Website{}, err } - tools.Exec("systemctl reload openresty") + if _, err := tools.Exec("systemctl reload openresty"); err != nil { + return models.Website{}, err + } 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;"`) + if _, err := 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;"`); err != nil { + return models.Website{}, err + } + if _, err := tools.Exec(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE USER '` + website.DbUser + `'@'localhost' IDENTIFIED BY '` + website.DbPassword + `';"`); err != nil { + return models.Website{}, err + } + if _, err := tools.Exec(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "GRANT ALL PRIVILEGES ON ` + website.DbName + `.* TO '` + website.DbUser + `'@'localhost';"`); err != nil { + return models.Website{}, err + } + if _, err := tools.Exec(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "FLUSH PRIVILEGES;"`); err != nil { + return models.Website{}, err + } } 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"`) + if _, err := tools.Exec(`echo "CREATE DATABASE ` + website.DbName + `;" | su - postgres -c "psql"`); err != nil { + return models.Website{}, err + } + if _, err := tools.Exec(`echo "CREATE USER ` + website.DbUser + ` WITH PASSWORD '` + website.DbPassword + `';" | su - postgres -c "psql"`); err != nil { + return models.Website{}, err + } + if _, err := tools.Exec(`echo "ALTER DATABASE ` + website.DbName + ` OWNER TO ` + website.DbUser + `;" | su - postgres -c "psql"`); err != nil { + return models.Website{}, err + } + if _, err := tools.Exec(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + website.DbName + ` TO ` + website.DbUser + `;" | su - postgres -c "psql"`); err != nil { + return models.Website{}, err + } } return w, nil @@ -331,7 +330,10 @@ func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error { if err := tools.Write("/www/server/vhost/"+website.Name+".conf", config.Raw, 0644); err != nil { return err } - tools.Exec("systemctl reload openresty") + if _, err := tools.Exec("systemctl reload openresty"); err != nil { + return err + } + return nil } @@ -509,8 +511,9 @@ func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error { if err := tools.Write("/www/server/vhost/rewrite/"+website.Name+".conf", config.Rewrite, 0644); err != nil { return err } - tools.Exec("systemctl reload openresty") - return nil + + _, err := tools.Exec("systemctl reload openresty") + return err } // Delete 删除网站 @@ -534,9 +537,8 @@ func (r *WebsiteImpl) Delete(id uint) error { tools.Remove("/www/server/vhost/ssl/" + website.Name + ".key") tools.Remove(website.Path) - tools.Exec("systemctl reload openresty") - - return nil + _, err := tools.Exec("systemctl reload openresty") + return err } // GetConfig 获取网站配置 @@ -630,9 +632,10 @@ func (r *WebsiteImpl) GetConfig(id uint) (WebsiteSetting, error) { } setting.Rewrite = tools.Read("/www/server/vhost/rewrite/" + website.Name + ".conf") - setting.Log = tools.Escape(tools.Exec(`tail -n 100 '/www/wwwlogs/` + website.Name + `.log'`)) + log, err := tools.Exec(`tail -n 100 '/www/wwwlogs/` + website.Name + `.log'`) + setting.Log = log - return setting, nil + return setting, err } // GetConfigByName 根据网站名称获取网站配置 diff --git a/go.mod b/go.mod index f11ce534b5..4a3dd6d004 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/go-acme/lego/v4 v4.14.2 github.com/gookit/color v1.5.4 github.com/gookit/validate v1.5.1 - github.com/goravel/fiber v1.1.11-0.20231108081345-36e967f101d0 - github.com/goravel/framework v1.13.1-0.20231110075143-376f1d9f92e1 + github.com/goravel/fiber v1.1.11-0.20231113090419-d5dad0a0021b + github.com/goravel/framework v1.13.1-0.20231113084434-6b10569a75f5 github.com/iancoleman/strcase v0.3.0 github.com/imroc/req/v3 v3.42.1 github.com/mojocn/base64Captcha v1.3.5 @@ -19,8 +19,7 @@ require ( github.com/swaggo/files/v2 v2.0.0 github.com/swaggo/swag v1.16.2 github.com/valyala/fasthttp v1.50.0 - golang.org/x/crypto v0.14.0 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d + golang.org/x/crypto v0.15.0 ) require ( @@ -81,9 +80,9 @@ require ( github.com/gofiber/utils v1.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/golang-jwt/jwt/v5 v5.0.0 // indirect + github.com/golang-jwt/jwt/v5 v5.1.0 // indirect github.com/golang-migrate/migrate/v4 v4.16.2 // indirect - github.com/golang-module/carbon/v2 v2.2.12 // indirect + github.com/golang-module/carbon/v2 v2.2.13 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect @@ -190,6 +189,7 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/arch v0.6.0 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/image v0.11.0 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect diff --git a/go.sum b/go.sum index ab596c57c7..1d3d79dabf 100644 --- a/go.sum +++ b/go.sum @@ -269,12 +269,13 @@ github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= +github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-migrate/migrate/v4 v4.16.2 h1:8coYbMKUyInrFk1lfGfRovTLAW7PhWp8qQDT2iKfuoA= github.com/golang-migrate/migrate/v4 v4.16.2/go.mod h1:pfcJX4nPHaVdc5nmdCikFBWtm+UBpiZjRNNsyBbp0/o= -github.com/golang-module/carbon/v2 v2.2.12 h1:qydcu64b5+29dOnMNVS27V3JaphyA2eLrUvKv8CNPMI= -github.com/golang-module/carbon/v2 v2.2.12/go.mod h1:XDALX7KgqmHk95xyLeaqX9/LJGbfLATyruTziq68SZ8= +github.com/golang-module/carbon/v2 v2.2.13 h1:8BzSrasTFP4sIXA78i4I4LxxlIxetwGOUGu/+WfjdVg= +github.com/golang-module/carbon/v2 v2.2.13/go.mod h1:XDALX7KgqmHk95xyLeaqX9/LJGbfLATyruTziq68SZ8= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= @@ -379,14 +380,14 @@ github.com/gookit/goutil v0.6.14 h1:96elyOG4BvVoDaiT7vx1vHPrVyEtFfYlPPBODR0/FGQ= github.com/gookit/goutil v0.6.14/go.mod h1:YyDBddefmjS+mU2PDPgCcjVzTDM5WgExiDv5ZA/b8I8= github.com/gookit/validate v1.5.1 h1:rPp64QZQJM+fysGFAhKpvekQAav4Ok6sjfTs9ZtxcpA= github.com/gookit/validate v1.5.1/go.mod h1:SskOHUQokzMNt6T3r7N+N/4me/6fxDx+tmoXf/3ZQog= -github.com/goravel/fiber v1.1.11-0.20231108081345-36e967f101d0 h1:mEuJdUWmNXIrg5njcbOS+GucmOM2QrqAHL+ODTgDHPo= -github.com/goravel/fiber v1.1.11-0.20231108081345-36e967f101d0/go.mod h1:IOvZ0G1bojUU/Kv9DZl+/8cwGhcNr0YRhwElz0hpjTg= +github.com/goravel/fiber v1.1.11-0.20231113090419-d5dad0a0021b h1:RPUhnDbyVmyl7CJhIyqxQMX7KlQfmxkiJ8BT5vgh2q4= +github.com/goravel/fiber v1.1.11-0.20231113090419-d5dad0a0021b/go.mod h1:oWPUDnztciFw4cSAk5CskLXYE0Joe9fWQanLNR39tIA= github.com/goravel/file-rotatelogs v0.0.0-20211215053220-2ab31dd9575c h1:obhFK91JAhcf7s6h5sggZishm1VyGW/gBCreo+7/SwQ= github.com/goravel/file-rotatelogs v0.0.0-20211215053220-2ab31dd9575c/go.mod h1:YSWsLXlG16u5CWFaXNZHhEQD10+NwF3xfgDV816OwLE= github.com/goravel/file-rotatelogs/v2 v2.4.1 h1:ogkeIFcTHSBRUBpZYiyJbpul8hkVXxHPuDbOaP78O1M= github.com/goravel/file-rotatelogs/v2 v2.4.1/go.mod h1:euk9qr52WrzM8ICs1hecFcR4CZ/ZZOPdacHfvHgbOf0= -github.com/goravel/framework v1.13.1-0.20231110075143-376f1d9f92e1 h1:J0FjRp0EGsyno2XNfUHIz2ghuE0dyg2/VUlR10/KRZA= -github.com/goravel/framework v1.13.1-0.20231110075143-376f1d9f92e1/go.mod h1:9vNb8pNm1HBF/1I4SOD88F5rP+/SvzrniJDx9t15OzU= +github.com/goravel/framework v1.13.1-0.20231113084434-6b10569a75f5 h1:Vh3xNLjnFyeJ+xecIE/FeISIV3ti+tuiKcntN0bKP5Y= +github.com/goravel/framework v1.13.1-0.20231113084434-6b10569a75f5/go.mod h1:EOMHWx6zpEgu12vIVglYuq1zNH/SXo+zeWsumY0esgo= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -744,8 +745,8 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58 golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -937,7 +938,7 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/tools/service.go b/pkg/tools/service.go new file mode 100644 index 0000000000..8c14c5efe3 --- /dev/null +++ b/pkg/tools/service.go @@ -0,0 +1,33 @@ +package tools + +import "fmt" + +// ServiceStatus 获取服务状态 +func ServiceStatus(name string) (bool, error) { + output, err := Exec(fmt.Sprintf("systemctl status %s | grep Active | grep -v grep | awk '{print $2}'", name)) + return output == "active", err +} + +// ServiceStart 启动服务 +func ServiceStart(name string) error { + _, err := Exec(fmt.Sprintf("systemctl start %s", name)) + return err +} + +// ServiceStop 停止服务 +func ServiceStop(name string) error { + _, err := Exec(fmt.Sprintf("systemctl stop %s", name)) + return err +} + +// ServiceRestart 重启服务 +func ServiceRestart(name string) error { + _, err := Exec(fmt.Sprintf("systemctl restart %s", name)) + return err +} + +// ServiceReload 重载服务 +func ServiceReload(name string) error { + _, err := Exec(fmt.Sprintf("systemctl reload %s", name)) + return err +} diff --git a/pkg/tools/system.go b/pkg/tools/system.go index 92a84e511b..897e9e412e 100644 --- a/pkg/tools/system.go +++ b/pkg/tools/system.go @@ -7,7 +7,6 @@ import ( "path/filepath" "strings" - "github.com/goravel/framework/facades" "github.com/goravel/framework/support" ) @@ -26,13 +25,10 @@ func Write(path string, data string, permission os.FileMode) error { } // Read 读取文件 +// TODO 重构带 error 返回 func Read(path string) string { data, err := os.ReadFile(path) if err != nil { - facades.Log().With(map[string]any{ - "path": path, - "error": err.Error(), - }).Tags("面板", "工具函数").Info("读取文件失败") return "" } @@ -40,12 +36,9 @@ func Read(path string) string { } // Remove 删除文件/目录 +// TODO 重构带 error 返回 func Remove(path string) bool { if err := os.RemoveAll(path); err != nil { - facades.Log().With(map[string]any{ - "path": path, - "error": err.Error(), - }).Tags("面板", "工具函数").Info("删除文件/目录失败") return false } @@ -53,25 +46,11 @@ func Remove(path string) bool { } // Exec 执行 shell 命令 -func Exec(shell string) string { - cmd := exec.Command("bash", "-c", shell) +func Exec(shell string) (string, error) { + cmd := exec.Command("bash", "-c", "LC_ALL=C "+shell) output, err := cmd.CombinedOutput() - if err != nil { - if support.Env == support.EnvTest { - fmt.Println(string(output)) - fmt.Println(err.Error()) - panic(err) - } else { - facades.Log().With(map[string]any{ - "shell": shell, - "error": err.Error(), - }).Tags("面板", "工具函数").Info("执行命令失败") - } - return "" - } - - return strings.TrimSpace(string(output)) + return strings.TrimSpace(string(output)), err } // ExecAsync 异步执行 shell 命令 @@ -88,11 +67,6 @@ func ExecAsync(shell string) error { if support.Env == support.EnvTest { fmt.Println(err.Error()) panic(err) - } else { - facades.Log().With(map[string]any{ - "shell": shell, - "error": err.Error(), - }).Tags("面板", "工具函数").Info("异步执行命令失败") } } }() diff --git a/pkg/tools/system_test.go b/pkg/tools/system_test.go index 308a884bd2..a0178e10b9 100644 --- a/pkg/tools/system_test.go +++ b/pkg/tools/system_test.go @@ -48,7 +48,9 @@ func (s *SystemHelperTestSuite) TestRemove() { } func (s *SystemHelperTestSuite) TestExec() { - s.Equal("test", Exec("echo 'test'")) + output, err := Exec("echo 'test'") + s.Equal("test", output) + s.Nil(err) } func (s *SystemHelperTestSuite) TestExecAsync() { diff --git a/pkg/tools/tools.go b/pkg/tools/tools.go index 08a67d5b3c..8c53cf6052 100644 --- a/pkg/tools/tools.go +++ b/pkg/tools/tools.go @@ -165,15 +165,16 @@ type PanelInfo struct { func GetLatestPanelVersion() (PanelInfo, error) { var info PanelInfo var output string + var err error isChina := IsChina() if isChina { - output = Exec(`curl -sSL "https://jihulab.com/api/v4/projects/haozi-team%2Fpanel/releases/permalink/latest"`) + output, err = Exec(`curl -sSL "https://jihulab.com/api/v4/projects/haozi-team%2Fpanel/releases/permalink/latest"`) } else { - output = Exec(`curl -sSL "https://api.github.com/repos/haozi-team/panel/releases/latest"`) + output, err = Exec(`curl -sSL "https://api.github.com/repos/haozi-team/panel/releases/latest"`) } - if len(output) == 0 { + if len(output) == 0 || err != nil { return info, errors.New("获取最新版本失败") } @@ -194,32 +195,72 @@ func GetLatestPanelVersion() (PanelInfo, error) { var name, version, body, date, downloadName, downloadUrl, checksums, checksumsUrl string if isChina { - name = Exec("jq -r '.name' " + fileName) - version = Exec("jq -r '.tag_name' " + fileName) - body = Exec("jq -r '.description' " + fileName) - date = Exec("jq -r '.created_at' " + fileName) - checksums = Exec("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .name' " + fileName) - checksumsUrl = Exec("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .direct_asset_url' " + fileName) + if name, err = Exec("jq -r '.name' " + fileName); err != nil { + return info, errors.New("获取最新版本失败") + } + if version, err = Exec("jq -r '.tag_name' " + fileName); err != nil { + return info, errors.New("获取最新版本失败") + } + if body, err = Exec("jq -r '.description' " + fileName); err != nil { + return info, errors.New("获取最新版本失败") + } + if date, err = Exec("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 { + return info, errors.New("获取最新版本失败") + } + if checksumsUrl, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .direct_asset_url' " + fileName); err != nil { + return info, errors.New("获取最新版本失败") + } if IsArm() { - downloadName = Exec("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .name' " + fileName) - downloadUrl = Exec("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .direct_asset_url' " + fileName) + if downloadName, err = Exec("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 { + return info, errors.New("获取最新版本失败") + } } else { - downloadName = Exec("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName) - downloadUrl = Exec("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .direct_asset_url' " + fileName) + if downloadName, err = Exec("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 { + return info, errors.New("获取最新版本失败") + } } } else { - name = Exec("jq -r '.name' " + fileName) - version = Exec("jq -r '.tag_name' " + fileName) - body = Exec("jq -r '.body' " + fileName) - date = Exec("jq -r '.published_at' " + fileName) - checksums = Exec("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .name' " + fileName) - checksumsUrl = Exec("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .browser_download_url' " + fileName) + if name, err = Exec("jq -r '.name' " + fileName); err != nil { + return info, errors.New("获取最新版本失败") + } + if version, err = Exec("jq -r '.tag_name' " + fileName); err != nil { + return info, errors.New("获取最新版本失败") + } + if body, err = Exec("jq -r '.body' " + fileName); err != nil { + return info, errors.New("获取最新版本失败") + } + if date, err = Exec("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 { + return info, errors.New("获取最新版本失败") + } + if checksumsUrl, err = Exec("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .browser_download_url' " + fileName); err != nil { + return info, errors.New("获取最新版本失败") + } if IsArm() { - downloadName = Exec("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .name' " + fileName) - downloadUrl = Exec("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .browser_download_url' " + fileName) + if downloadName, err = Exec("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 { + return info, errors.New("获取最新版本失败") + } } else { - downloadName = Exec("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName) - downloadUrl = Exec("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .browser_download_url' " + fileName) + if downloadName, err = Exec("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 { + return info, errors.New("获取最新版本失败") + } } } @@ -239,6 +280,7 @@ func GetLatestPanelVersion() (PanelInfo, error) { func GetPanelVersion(version string) (PanelInfo, error) { var info PanelInfo var output string + var err error isChina := IsChina() if !strings.HasPrefix(version, "v") { @@ -246,12 +288,12 @@ func GetPanelVersion(version string) (PanelInfo, error) { } if isChina { - output = Exec(`curl -sSL "https://jihulab.com/api/v4/projects/haozi-team%2Fpanel/releases/` + version + `"`) + output, err = Exec(`curl -sSL "https://jihulab.com/api/v4/projects/haozi-team%2Fpanel/releases/` + version + `"`) } else { - output = Exec(`curl -sSL "https://api.github.com/repos/haozi-team/panel/releases/tags/` + version + `"`) + output, err = Exec(`curl -sSL "https://api.github.com/repos/haozi-team/panel/releases/tags/` + version + `"`) } - if len(output) == 0 { + if len(output) == 0 || err != nil { return info, errors.New("获取面板版本失败") } @@ -272,32 +314,72 @@ func GetPanelVersion(version string) (PanelInfo, error) { var name, version2, body, date, downloadName, downloadUrl, checksums, checksumsUrl string if isChina { - name = Exec("jq -r '.name' " + fileName) - version2 = Exec("jq -r '.tag_name' " + fileName) - body = Exec("jq -r '.description' " + fileName) - date = Exec("jq -r '.created_at' " + fileName) - checksums = Exec("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .name' " + fileName) - checksumsUrl = Exec("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .direct_asset_url' " + fileName) + if name, err = Exec("jq -r '.name' " + fileName); err != nil { + return info, errors.New("获取面板版本失败") + } + if version2, err = Exec("jq -r '.tag_name' " + fileName); err != nil { + return info, errors.New("获取面板版本失败") + } + if body, err = Exec("jq -r '.description' " + fileName); err != nil { + return info, errors.New("获取面板版本失败") + } + if date, err = Exec("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 { + return info, errors.New("获取面板版本失败") + } + if checksumsUrl, err = Exec("jq -r '.assets.links[] | select(.name | contains(\"checksums\")) | .direct_asset_url' " + fileName); err != nil { + return info, errors.New("获取面板版本失败") + } if IsArm() { - downloadName = Exec("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .name' " + fileName) - downloadUrl = Exec("jq -r '.assets.links[] | select(.name | contains(\"arm64\")) | .direct_asset_url' " + fileName) + if downloadName, err = Exec("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 { + return info, errors.New("获取面板版本失败") + } } else { - downloadName = Exec("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName) - downloadUrl = Exec("jq -r '.assets.links[] | select(.name | contains(\"amd64v2\")) | .direct_asset_url' " + fileName) + if downloadName, err = Exec("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 { + return info, errors.New("获取面板版本失败") + } } } else { - name = Exec("jq -r '.name' " + fileName) - version2 = Exec("jq -r '.tag_name' " + fileName) - body = Exec("jq -r '.body' " + fileName) - date = Exec("jq -r '.published_at' " + fileName) - checksums = Exec("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .name' " + fileName) - checksumsUrl = Exec("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .browser_download_url' " + fileName) + if name, err = Exec("jq -r '.name' " + fileName); err != nil { + return info, errors.New("获取面板版本失败") + } + if version2, err = Exec("jq -r '.tag_name' " + fileName); err != nil { + return info, errors.New("获取面板版本失败") + } + if body, err = Exec("jq -r '.body' " + fileName); err != nil { + return info, errors.New("获取面板版本失败") + } + if date, err = Exec("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 { + return info, errors.New("获取面板版本失败") + } + if checksumsUrl, err = Exec("jq -r '.assets[] | select(.name | contains(\"checksums\")) | .browser_download_url' " + fileName); err != nil { + return info, errors.New("获取面板版本失败") + } if IsArm() { - downloadName = Exec("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .name' " + fileName) - downloadUrl = Exec("jq -r '.assets[] | select(.name | contains(\"arm64\")) | .browser_download_url' " + fileName) + if downloadName, err = Exec("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 { + return info, errors.New("获取面板版本失败") + } } else { - downloadName = Exec("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .name' " + fileName) - downloadUrl = Exec("jq -r '.assets[] | select(.name | contains(\"amd64v2\")) | .browser_download_url' " + fileName) + if downloadName, err = Exec("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 { + return info, errors.New("获取面板版本失败") + } } } @@ -319,58 +401,100 @@ func UpdatePanel(panelInfo PanelInfo) error { color.Greenln("下载链接: " + panelInfo.DownloadUrl) color.Greenln("备份面板配置...") - Exec("cp -f /www/panel/database/panel.db /tmp/panel.db.bak") - Exec("cp -f /www/panel/panel.conf /tmp/panel.conf.bak") + if _, err := Exec("cp -f /www/panel/database/panel.db /tmp/panel.db.bak"); err != nil { + color.Redln("备份面板数据库失败") + return err + } + if _, err := Exec("cp -f /www/panel/panel.conf /tmp/panel.conf.bak"); err != nil { + color.Redln("备份面板配置失败") + return err + } if !Exists("/tmp/panel.db.bak") || !Exists("/tmp/panel.conf.bak") { return errors.New("备份面板配置失败") } color.Greenln("备份完成") color.Greenln("清理旧版本...") - Exec("rm -rf /www/panel/*") + if _, err := Exec("rm -rf /www/panel/*"); err != nil { + color.Redln("清理旧版本失败") + return err + } color.Greenln("清理完成") color.Greenln("正在下载...") - Exec("wget -T 120 -t 3 -O /www/panel/" + panelInfo.DownloadName + " " + panelInfo.DownloadUrl) - Exec("wget -T 20 -t 3 -O /www/panel/" + panelInfo.Checksums + " " + panelInfo.ChecksumsUrl) + if _, err := Exec("wget -T 120 -t 3 -O /www/panel/" + panelInfo.DownloadName + " " + panelInfo.DownloadUrl); err != nil { + color.Redln("下载失败") + return err + } + if _, err := Exec("wget -T 20 -t 3 -O /www/panel/" + panelInfo.Checksums + " " + panelInfo.ChecksumsUrl); err != nil { + color.Redln("下载失败") + return err + } if !Exists("/www/panel/"+panelInfo.DownloadName) || !Exists("/www/panel/"+panelInfo.Checksums) { return errors.New("下载失败") } color.Greenln("下载完成") color.Greenln("校验下载文件...") - check := Exec("cd /www/panel && sha256sum -c " + panelInfo.Checksums + " --ignore-missing") - if check != panelInfo.DownloadName+": OK" { + check, err := Exec("cd /www/panel && sha256sum -c " + panelInfo.Checksums + " --ignore-missing") + if check != panelInfo.DownloadName+": OK" || err != nil { return errors.New("下载文件校验失败") } Remove("/www/panel/" + panelInfo.Checksums) color.Greenln("文件校验完成") color.Greenln("更新新版本...") - Exec("cd /www/panel && unzip -o " + panelInfo.DownloadName + " && rm -rf " + panelInfo.DownloadName) + if _, err = Exec("cd /www/panel && unzip -o " + panelInfo.DownloadName + " && rm -rf " + panelInfo.DownloadName); err != nil { + color.Redln("更新失败") + return err + } if !Exists("/www/panel/panel") { return errors.New("更新失败,可能是下载过程中出现了问题") } color.Greenln("更新完成") color.Greenln("恢复面板配置...") - Exec("cp -f /tmp/panel.db.bak /www/panel/database/panel.db") - Exec("cp -f /tmp/panel.conf.bak /www/panel/panel.conf") + if _, err = Exec("cp -f /tmp/panel.db.bak /www/panel/database/panel.db"); err != nil { + color.Redln("恢复面板数据库失败") + return err + } + if _, err = Exec("cp -f /tmp/panel.conf.bak /www/panel/panel.conf"); err != nil { + color.Redln("恢复面板配置失败") + return err + } if !Exists("/www/panel/database/panel.db") || !Exists("/www/panel/panel.conf") { return errors.New("恢复面板配置失败") } - Exec("/www/panel/panel --env=panel.conf artisan migrate") + if _, err = Exec("/www/panel/panel --env=panel.conf artisan migrate"); err != nil { + color.Redln("运行面板数据库迁移失败") + return err + } color.Greenln("恢复完成") color.Greenln("设置面板文件权限...") - Exec("chmod -R 700 /www/panel") + if _, err = Exec("chmod -R 700 /www/panel"); err != nil { + color.Redln("设置面板文件权限失败") + return err + } color.Greenln("设置完成") - Exec("bash /www/panel/scripts/update_panel.sh") - Exec("panel writeSetting version " + panelInfo.Version) + if _, err = Exec("bash /www/panel/scripts/update_panel.sh"); err != nil { + color.Redln("执行面板升级后脚本失败") + return err + } + if _, err = Exec("panel writeSetting version " + panelInfo.Version); err != nil { + color.Redln("写入面板版本号失败") + return err + } - Exec("rm -rf /tmp/panel.db.bak") - Exec("rm -rf /tmp/panel.conf.bak") + if _, err = Exec("rm -rf /tmp/panel.db.bak"); err != nil { + color.Redln("清理临时文件失败") + return err + } + if _, err = Exec("rm -rf /tmp/panel.conf.bak"); err != nil { + color.Redln("清理临时文件失败") + return err + } return nil }