mirror of
https://github.com/tnb-labs/panel.git
synced 2026-08-31 01:12:17 +08:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 83d7aec8f5 | |||
| b43e5b5c80 | |||
| acb792950a | |||
| 41d83719ff | |||
| de1c269a4a | |||
| c3bf62ebf7 | |||
| 317851d982 | |||
| f52d95ae11 | |||
| 6420092c90 | |||
| 2fa108dd67 | |||
| 86bfcfb9f1 | |||
| db65a493dc | |||
| 4dd99a149c | |||
| 5d1fbb2e2b | |||
| 94569cca02 | |||
| 905aaf102b | |||
| d91aa666cc | |||
| 4f90bbc177 | |||
| f6c3bd27fd | |||
| 137c5ceba4 | |||
| c6f5b99373 | |||
| d7f647a8db | |||
| 77277a6af6 | |||
| d9acaec3c5 | |||
| c8692844b6 | |||
| 0b49301e9e | |||
| 30fded4552 | |||
| 9b3b76d1d0 | |||
| f37f22b86b | |||
| 52eedad3da | |||
| 0e2dda597f | |||
| 313511b474 | |||
| d2ed2b5082 | |||
| cce19e1a64 | |||
| 62b84a8909 | |||
| ff7b4f5f3b | |||
| 43a8d8cc2a | |||
| bf09ffd316 | |||
| b0d08e2901 | |||
| 62684ccfda | |||
| 6353231f4a | |||
| 6abd6b139f | |||
| 40358b2551 | |||
| 6e6342f0a6 | |||
| cea485133f | |||
| 08e14a84a5 | |||
| bc179923a0 | |||
| 67ef7ccd7a | |||
| 1abb9691f4 |
@@ -1,25 +0,0 @@
|
||||
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gomod
|
||||
directory: /
|
||||
labels:
|
||||
- "🤖 Dependencies"
|
||||
schedule:
|
||||
interval: daily
|
||||
groups:
|
||||
go-modules:
|
||||
patterns:
|
||||
- "*"
|
||||
open-pull-requests-limit: 100
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
labels:
|
||||
- "🤖 Dependencies"
|
||||
schedule:
|
||||
interval: daily
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
open-pull-requests-limit: 100
|
||||
@@ -1,22 +0,0 @@
|
||||
name: Code Review
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [ opened, reopened, synchronize, labeled ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
if: ${{ contains(github.event.pull_request.labels.*.name, '🚀 Review Ready') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: anc95/ChatGPT-CodeReview@main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
OPENAI_API_ENDPOINT: https://api.openai-sb.com/v1
|
||||
MODEL: gpt-3.5-turbo
|
||||
PROMPT: "Below is a code patch, please help me do a brief code review on it. Only answer important bug risks and/or important improvement suggestions, Answer in Chinese and answer must be concisely and short: "
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
我们认为您的建议非常有价值!欢迎提交 PR,请包含相应的测试用例、文档等,并确保 CI 通过,感谢和期待您的贡献!
|
||||
We think your suggestion is very valuable! Welcome to submit a PR, please include test cases, documentation, etc., and ensure that the CI is passed, thank you and look forward to your contribution!
|
||||
|
||||
"Talk is cheap, Show me the Code." - Linus Torvalds
|
||||

|
||||
- name: ☢️ Bug
|
||||
if: github.event.label.name == '☢️ Bug'
|
||||
uses: actions-cool/issues-helper@v3
|
||||
@@ -41,4 +41,4 @@ jobs:
|
||||
我们认为您的反馈非常有价值!欢迎提交 PR,请包含相应的测试用例、文档等,并确保 CI 通过,感谢和期待您的贡献!
|
||||
We think your feedback is very valuable! Welcome to submit a PR, please include test cases, documentation, etc., and ensure that the CI is passed, thank you and look forward to your contribution!
|
||||
|
||||
"Talk is cheap, Show me the Code." - Linus Torvalds
|
||||

|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
name: PR Check Title
|
||||
on:
|
||||
pull_request:
|
||||
jobs:
|
||||
pr-check-title:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Slashgear/action-check-pr-title@v4.3.0
|
||||
with:
|
||||
regexp: "^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release|revert)(\\(.+\\))?!?: .+"
|
||||
helpMessage: "Your PR title is invalid. Please follow the Conventional Commits specification: https://www.conventionalcommits.org/zh-hans/v1.0.0/"
|
||||
@@ -6,30 +6,36 @@
|
||||
[](https://codecov.io/gh/haozi-team/panel)
|
||||

|
||||
|
||||
这是耗子Linux面板的开源仓库,基于Apache License 2.0协议进行开源,目前处于积极开发状态。
|
||||
这是耗子Linux面板,一种使用GO开发的轻量Linux服务器运维管理面板。
|
||||
|
||||
#### 交流QQ群:[12370907](https://jq.qq.com/?_wv=1027&k=I1oJKSTH) | QQ频道:[耗子](https://pd.qq.com/s/fyol46wfy)
|
||||
通知:严禁使用耗子Linux面板从事任何非法活动,非法站点请勿向我们请求任何形式的技术支持,如果在技术支持过程中发现非法内容,我们将立即停止技术支持并留存相关证据。
|
||||
|
||||
#### 交流QQ群:[12370907](https://jq.qq.com/?_wv=1027&k=I1oJKSTH) | QQ频道:[pd.qq.com/s/fyol46wfy](https://pd.qq.com/s/fyol46wfy)
|
||||
|
||||
广告: [`WeAvatar` 多端多元化的统一头像服务](https://weavatar.com)
|
||||
|
||||
## 运行环境
|
||||
|
||||
面板仅支持主流 `amd64` | `arm64` 系统的最新版本,且随着系统版本的更新,面板也会逐步停止对旧版本的支持。
|
||||
面板仅支持主流 `amd64` | `arm64` 系统的最新版本,且随着系统版本的更新,面板也会逐步停止对旧版本系统的支持。
|
||||
|
||||
不支持 `Ubuntu`,因为其发版太频繁,难以维护。
|
||||
不支持 `Ubuntu`,因为其发版太过频繁,难以维护。
|
||||
|
||||
低配机器建议使用 `Debian`,资源占用较 `RHEL` 系更低。其他机器建议使用 `RockyLinux` | `AlmaLinux`,维护周期更长。
|
||||
|
||||
不在下表中的其他同版本的 `RHEL` 系统(OpenCloudOS、Anolis、CentOS Stream等),可自行尝试安装,但不保证能够正常运行,且不提供技术支持。
|
||||
不在下表中的其他系统(OpenCloudOS 8、Anolis 8、CentOS Stream 8/9、Debian 11等),可自行尝试安装,但不保证能够正常运行,且不提供技术支持(理论上不会有大问题)。
|
||||
|
||||
| 系统 | 版本 |
|
||||
|------------|----|
|
||||
| RHEL | 9 |
|
||||
| RockyLinux | 9 |
|
||||
| AlmaLinux | 9 |
|
||||
| Debian | 12 |
|
||||
|
||||
## 安装面板
|
||||
|
||||
安装面板前,你需要了解LNMP环境的基本知识,以及如何处理常见的LNMP环境问题,我们不建议0基础的用户安装和使用耗子Linux面板。
|
||||
|
||||
如果你决定继续,请以`root`用户登录服务器,执行以下命令安装面板:
|
||||
|
||||
```shell
|
||||
bash <(curl -sSL https://dl.cdn.haozi.net/panel/install_panel.sh)
|
||||
@@ -37,18 +43,33 @@ bash <(curl -sSL https://dl.cdn.haozi.net/panel/install_panel.sh)
|
||||
|
||||
## 日常维护
|
||||
|
||||
使用`panel`命令进行日常维护:
|
||||
|
||||
```shell
|
||||
panel
|
||||
```
|
||||
|
||||
## 问题反馈
|
||||
|
||||
使用类问题,可在 [WePublish社区论坛](https://wepublish.cn/forums) 提问寻求帮助。
|
||||
使用类问题,可在 [WePublish社区论坛](https://wepublish.cn/forums) 提问或QQ群`@汤姆猫`寻求帮助。
|
||||
|
||||
对于面板自身问题,可在 GitHub 的`Issues`
|
||||
面板自身问题,可在 GitHub 的`Issues`
|
||||
页面提交问题反馈,注意[提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md)。
|
||||
|
||||
交流QQ群:[12370907](https://jq.qq.com/?_wv=1027&k=I1oJKSTH) | QQ频道:[耗子](https://pd.qq.com/s/fyol46wfy)
|
||||
## 贡献代码
|
||||
|
||||
### 寻找/创建 Issue
|
||||
|
||||
您可以在 [Issue 列表](https://github.com/haozi-team/panel/issues) 中寻找或创建一个 Issue,留言表达想要处理该 Issue
|
||||
的意愿,得到维护者的确认后,即可开始处理。
|
||||
|
||||
### 创建 PR
|
||||
|
||||
- 在开发过程中,如果遇到问题可以随时在 Issue 中详尽描述该问题,以进一步沟通,但在此之前请确保自己已通过 Google
|
||||
等方式尽可能的尝试解决问题;
|
||||
- PR 须提交至我们的极狐GitLab仓库[https://jihulab.com/haozi-team/panel](https://jihulab.com/haozi-team/panel)
|
||||
- 当 PR 开发完毕后,请为其添加 `🚀 Review Ready` 标签,维护者将及时进行评审;
|
||||
- 我们非常欢迎您的贡献,将在下次发版时将您添加到首页贡献者中;❤️
|
||||
|
||||
## 赞助商
|
||||
|
||||
@@ -62,12 +83,48 @@ panel
|
||||
|
||||
- [无畏云加速](https://su.sctes.com/register?code=8st689ujpmm2p)
|
||||
|
||||
- [AnyCast.Ai](https://www.anycast.ai/)
|
||||
|
||||
- [迅捷盾](https://console.fastdun.com/)
|
||||
|
||||
### DevOps
|
||||
|
||||
- [极狐GitLab](https://www.jihulab.com/)
|
||||
|
||||
#### 接受云资源和资金赞助,可通过QQ群咨询联系
|
||||
|
||||
## Star 趋势
|
||||
## 行为准则
|
||||
|
||||
[](https://starchart.cc/haozi-team/panel)
|
||||
耗子Linux面板遵守业界通用的行为准则。任何违反行为准则的行为都可以报告给我们:
|
||||
|
||||
- 参与者将容忍反对意见。
|
||||
- 参与者必须确保他们的语言和行为没有人身攻击和贬低个人言论。
|
||||
- 在解释他人的言行时,参与者应始终保持良好的意图。
|
||||
- 不能容忍可合理视为骚扰的行为。
|
||||
|
||||
## 安全说明
|
||||
|
||||
安全性是我们最关心的问题之一,我们已在生产环境广泛应用耗子Linux面板。
|
||||
|
||||
耗子Linux面板采用业界多种方案尽可能保证面板的安全性,但是我们不能保证面板的绝对安全性,**因此我们不对面板的安全性做任何保证**。
|
||||
|
||||
如果您在使用面板的过程中发现任何安全问题,请勿提交 Issue,可通过以下方式直接联系我们:
|
||||
|
||||
- 邮箱:i@haozi.net
|
||||
- QQ:826896000
|
||||
|
||||
## 贡献者
|
||||
|
||||
这个项目的存在要归功于所有做出贡献的人,参与贡献请先查看贡献代码部分。
|
||||
|
||||
<a href="https://github.com/DevHaoZi" target="_blank"><img src="https://avatars.githubusercontent.com/u/115467771?v=4" width="48" height="48"></a>
|
||||
|
||||
## Star 历史
|
||||
|
||||
<a href="https://star-history.com/#haozi-team/panel&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=haozi-team/panel&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=haozi-team/panel&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=haozi-team/panel&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@@ -55,7 +56,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
settings := []models.Setting{{Key: models.SettingKeyName, Value: "耗子Linux面板"}, {Key: models.SettingKeyMonitor, Value: "1"}, {Key: models.SettingKeyMonitorDays, Value: "30"}, {Key: models.SettingKeyBackupPath, Value: "/www/backup"}, {Key: models.SettingKeyWebsitePath, Value: "/www/wwwroot"}, {Key: models.SettingKeyEntrance, Value: "/"}}
|
||||
settings := []models.Setting{{Key: models.SettingKeyName, Value: "耗子Linux面板"}, {Key: models.SettingKeyMonitor, Value: "1"}, {Key: models.SettingKeyMonitorDays, Value: "30"}, {Key: models.SettingKeyBackupPath, Value: "/www/backup"}, {Key: models.SettingKeyWebsitePath, Value: "/www/wwwroot"}, {Key: models.SettingKeyEntrance, Value: "/"}, {Key: models.SettingKeyVersion, Value: facades.Config().GetString("panel.version")}}
|
||||
err = facades.Orm().Query().Create(&settings)
|
||||
if err != nil {
|
||||
color.Redln("初始化失败")
|
||||
@@ -122,7 +123,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
port := tools.ExecShell(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
|
||||
port := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
|
||||
|
||||
color.Greenln("用户名: " + user.Username)
|
||||
color.Greenln("密码: " + password)
|
||||
@@ -130,7 +131,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
color.Greenln("面板入口: " + services.NewSettingImpl().Get(models.SettingKeyEntrance, "/"))
|
||||
|
||||
case "getPort":
|
||||
port := tools.ExecShell("cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}'")
|
||||
port := tools.Exec("cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}'")
|
||||
color.Greenln("面板端口: " + port)
|
||||
|
||||
case "getEntrance":
|
||||
@@ -242,7 +243,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
}
|
||||
|
||||
backupFile := path + "/" + website.Name + "_" + carbon.Now().ToShortDateTimeString() + ".zip"
|
||||
tools.ExecShell(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`)
|
||||
tools.Exec(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`)
|
||||
color.Greenln("|-备份成功")
|
||||
|
||||
case "mysql":
|
||||
@@ -258,21 +259,24 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
|
||||
color.Greenln("|-目标MySQL数据库: " + name)
|
||||
color.Greenln("|-开始导出")
|
||||
tools.ExecShell(`mysqldump -uroot ` + name + ` > /tmp/` + backupFile + ` 2>&1`)
|
||||
tools.Exec(`mysqldump -uroot ` + name + ` > /tmp/` + backupFile + ` 2>&1`)
|
||||
color.Greenln("|-导出成功")
|
||||
color.Greenln("|-开始压缩")
|
||||
tools.ExecShell("cd /tmp && zip -r " + backupFile + ".zip " + backupFile)
|
||||
tools.RemoveFile("/tmp/" + backupFile)
|
||||
tools.Exec("cd /tmp && zip -r " + backupFile + ".zip " + backupFile)
|
||||
tools.Remove("/tmp/" + backupFile)
|
||||
color.Greenln("|-压缩成功")
|
||||
color.Greenln("|-开始移动")
|
||||
tools.Mv("/tmp/"+backupFile+".zip", path+"/"+backupFile+".zip")
|
||||
if _, err := tools.Mv("/tmp/"+backupFile+".zip", path+"/"+backupFile+".zip"); err != nil {
|
||||
color.Redln("|-移动失败: " + err.Error())
|
||||
return nil
|
||||
}
|
||||
color.Greenln("|-移动成功")
|
||||
_ = os.Unsetenv("MYSQL_PWD")
|
||||
color.Greenln("|-备份成功")
|
||||
|
||||
case "postgresql":
|
||||
backupFile := name + "_" + carbon.Now().ToShortDateTimeString() + ".sql"
|
||||
check := tools.ExecShell(`su - postgres -c "psql -l" 2>&1`)
|
||||
check := tools.Exec(`su - postgres -c "psql -l" 2>&1`)
|
||||
if strings.Contains(check, name) {
|
||||
color.Redln("|-数据库不存在")
|
||||
color.Greenln(hr)
|
||||
@@ -281,14 +285,17 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
|
||||
color.Greenln("|-目标PostgreSQL数据库: " + name)
|
||||
color.Greenln("|-开始导出")
|
||||
tools.ExecShell(`su - postgres -c "pg_dump '` + name + `'" > /tmp/` + backupFile + ` 2>&1`)
|
||||
tools.Exec(`su - postgres -c "pg_dump '` + name + `'" > /tmp/` + backupFile + ` 2>&1`)
|
||||
color.Greenln("|-导出成功")
|
||||
color.Greenln("|-开始压缩")
|
||||
tools.ExecShell("cd /tmp && zip -r " + backupFile + ".zip " + backupFile)
|
||||
tools.RemoveFile("/tmp/" + backupFile)
|
||||
tools.Exec("cd /tmp && zip -r " + backupFile + ".zip " + backupFile)
|
||||
tools.Remove("/tmp/" + backupFile)
|
||||
color.Greenln("|-压缩成功")
|
||||
color.Greenln("|-开始移动")
|
||||
tools.Mv("/tmp/"+backupFile+".zip", path+"/"+backupFile+".zip")
|
||||
if _, err := tools.Mv("/tmp/"+backupFile+".zip", path+"/"+backupFile+".zip"); err != nil {
|
||||
color.Redln("|-移动失败: " + err.Error())
|
||||
return nil
|
||||
}
|
||||
color.Greenln("|-移动成功")
|
||||
color.Greenln("|-备份成功")
|
||||
}
|
||||
@@ -315,7 +322,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
for i := cast.ToInt(save); i < len(filteredFiles); i++ {
|
||||
fileToDelete := filepath.Join(path, filteredFiles[i].Name())
|
||||
color.Yellowln("|-清理备份: " + fileToDelete)
|
||||
tools.RemoveFile(fileToDelete)
|
||||
tools.Remove(fileToDelete)
|
||||
}
|
||||
color.Greenln("|-清理完成")
|
||||
color.Greenln(hr)
|
||||
@@ -351,8 +358,8 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
}
|
||||
|
||||
backupPath := "/www/wwwlogs/" + website.Name + "_" + carbon.Now().ToShortDateTimeString() + ".log.zip"
|
||||
tools.ExecShell(`cd /www/wwwlogs && zip -r ` + backupPath + ` ` + website.Name + ".log")
|
||||
tools.ExecShell(`echo "" > ` + logPath)
|
||||
tools.Exec(`cd /www/wwwlogs && zip -r ` + backupPath + ` ` + website.Name + ".log")
|
||||
tools.Exec(`echo "" > ` + logPath)
|
||||
color.Greenln("|-切割成功")
|
||||
|
||||
color.Greenln(hr)
|
||||
@@ -377,7 +384,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
for i := cast.ToInt(save); i < len(filteredFiles); i++ {
|
||||
fileToDelete := filepath.Join("/www/wwwlogs", filteredFiles[i].Name())
|
||||
color.Yellowln("|-清理日志: " + fileToDelete)
|
||||
tools.RemoveFile(fileToDelete)
|
||||
tools.Remove(fileToDelete)
|
||||
}
|
||||
color.Greenln("|-清理完成")
|
||||
color.Greenln(hr)
|
||||
@@ -457,6 +464,20 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
|
||||
color.Greenln("写入设置成功")
|
||||
|
||||
case "getSetting":
|
||||
key := arg1
|
||||
if len(key) == 0 {
|
||||
color.Redln("参数错误")
|
||||
return nil
|
||||
}
|
||||
|
||||
var setting models.Setting
|
||||
if err := facades.Orm().Query().Where("key", key).FirstOrFail(&setting); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("%s", setting.Value)
|
||||
|
||||
case "deleteSetting":
|
||||
key := arg1
|
||||
if len(key) == 0 {
|
||||
@@ -490,6 +511,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
color.Yellowln("panel writeMysqlPassword {password} 写入MySQL root密码")
|
||||
color.Yellowln("panel writeSite {name} {status} {path} {php} {ssl} 写入网站数据到面板")
|
||||
color.Yellowln("panel deleteSite {name} 删除面板网站数据")
|
||||
color.Yellowln("panel getSetting {name} 获取面板设置数据")
|
||||
color.Yellowln("panel writeSetting {name} {value} 写入 / 更新面板设置数据")
|
||||
color.Yellowln("panel deleteSetting {name} 删除面板设置数据")
|
||||
}
|
||||
|
||||
@@ -123,12 +123,12 @@ panel cutoff ${name} ${save} 2>&1
|
||||
return
|
||||
}
|
||||
shellFile := strconv.Itoa(int(carbon.Now().Timestamp())) + tools.RandomString(16)
|
||||
if !tools.WriteFile(shellDir+shellFile+".sh", shell, 0700) {
|
||||
if !tools.Write(shellDir+shellFile+".sh", shell, 0700) {
|
||||
facades.Log().Error("[面板][CronController] 创建计划任务脚本失败 ", err)
|
||||
Error(ctx, http.StatusInternalServerError, "系统内部错误")
|
||||
return
|
||||
}
|
||||
tools.ExecShell("dos2unix " + shellDir + shellFile + ".sh")
|
||||
tools.Exec("dos2unix " + shellDir + shellFile + ".sh")
|
||||
|
||||
var cron models.Cron
|
||||
cron.Name = ctx.Request().Input("name")
|
||||
@@ -161,7 +161,7 @@ func (c *CronController) Script(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
Success(ctx, tools.ReadFile(cron.Shell))
|
||||
Success(ctx, tools.Read(cron.Shell))
|
||||
}
|
||||
|
||||
func (c *CronController) Update(ctx http.Context) {
|
||||
@@ -206,12 +206,12 @@ func (c *CronController) Update(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !tools.WriteFile(cron.Shell, ctx.Request().Input("script"), 0644) {
|
||||
if !tools.Write(cron.Shell, ctx.Request().Input("script"), 0644) {
|
||||
facades.Log().Error("[面板][CronController] 更新计划任务脚本失败 ", err)
|
||||
Error(ctx, http.StatusInternalServerError, "系统内部错误")
|
||||
return
|
||||
}
|
||||
tools.ExecShell("dos2unix " + cron.Shell)
|
||||
tools.Exec("dos2unix " + cron.Shell)
|
||||
|
||||
c.cron.DeleteFromSystem(cron)
|
||||
if cron.Status {
|
||||
@@ -230,7 +230,7 @@ func (c *CronController) Delete(ctx http.Context) {
|
||||
}
|
||||
|
||||
c.cron.DeleteFromSystem(cron)
|
||||
tools.RemoveFile(cron.Shell)
|
||||
tools.Remove(cron.Shell)
|
||||
|
||||
_, err = facades.Orm().Query().Delete(&cron)
|
||||
if err != nil {
|
||||
@@ -291,5 +291,5 @@ func (c *CronController) Log(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
Success(ctx, tools.ReadFile(cron.Log))
|
||||
Success(ctx, tools.Read(cron.Log))
|
||||
}
|
||||
|
||||
@@ -196,6 +196,6 @@ func (c *InfoController) Restart(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl restart panel")
|
||||
tools.Exec("systemctl restart panel")
|
||||
Success(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func (c *Fail2banController) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败")
|
||||
return
|
||||
@@ -58,8 +58,8 @@ func (c *Fail2banController) Reload(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl reload fail2ban")
|
||||
status := tools.ExecShell("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl reload fail2ban")
|
||||
status := tools.Exec("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败")
|
||||
return
|
||||
@@ -78,8 +78,8 @@ func (c *Fail2banController) Restart(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl restart fail2ban")
|
||||
status := tools.ExecShell("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl restart fail2ban")
|
||||
status := tools.Exec("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败")
|
||||
return
|
||||
@@ -98,8 +98,8 @@ func (c *Fail2banController) Start(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl start fail2ban")
|
||||
status := tools.ExecShell("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl start fail2ban")
|
||||
status := tools.Exec("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败")
|
||||
return
|
||||
@@ -118,8 +118,8 @@ func (c *Fail2banController) Stop(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl stop fail2ban")
|
||||
status := tools.ExecShell("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl stop fail2ban")
|
||||
status := tools.Exec("systemctl status fail2ban | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取服务运行状态失败")
|
||||
return
|
||||
@@ -140,7 +140,7 @@ func (c *Fail2banController) List(ctx http.Context) {
|
||||
|
||||
page := ctx.Request().QueryInt("page", 1)
|
||||
limit := ctx.Request().QueryInt("limit", 10)
|
||||
raw := tools.ReadFile("/etc/fail2ban/jail.local")
|
||||
raw := tools.Read("/etc/fail2ban/jail.local")
|
||||
if len(raw) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "Fail2ban 规则为空")
|
||||
return
|
||||
@@ -231,7 +231,7 @@ func (c *Fail2banController) Add(ctx http.Context) {
|
||||
jailWebsiteMode := ctx.Request().Input("website_mode")
|
||||
jailWebsitePath := ctx.Request().Input("website_path")
|
||||
|
||||
raw := tools.ReadFile("/etc/fail2ban/jail.local")
|
||||
raw := tools.Read("/etc/fail2ban/jail.local")
|
||||
if strings.Contains(raw, "["+jailName+"]") || (strings.Contains(raw, "["+jailName+"]"+"-cc") && jailWebsiteMode == "cc") || (strings.Contains(raw, "["+jailName+"]"+"-path") && jailWebsiteMode == "path") {
|
||||
controllers.Error(ctx, http.StatusUnprocessableEntity, "规则已存在")
|
||||
return
|
||||
@@ -273,7 +273,7 @@ logpath = /www/wwwlogs/` + website.Name + `.log
|
||||
# ` + jailName + `-` + jailWebsiteMode + `-END
|
||||
`
|
||||
raw += rule
|
||||
tools.WriteFile("/etc/fail2ban/jail.local", raw, 0644)
|
||||
tools.Write("/etc/fail2ban/jail.local", raw, 0644)
|
||||
|
||||
var filter string
|
||||
if jailWebsiteMode == "cc" {
|
||||
@@ -289,7 +289,7 @@ failregex = ^<HOST>\s-.*\s` + jailWebsitePath + `.*HTTP/.*$
|
||||
ignoreregex =
|
||||
`
|
||||
}
|
||||
tools.WriteFile("/etc/fail2ban/filter.d/haozi-"+jailName+"-"+jailWebsiteMode+".conf", filter, 0644)
|
||||
tools.Write("/etc/fail2ban/filter.d/haozi-"+jailName+"-"+jailWebsiteMode+".conf", filter, 0644)
|
||||
|
||||
case "service":
|
||||
var logPath string
|
||||
@@ -303,15 +303,15 @@ ignoreregex =
|
||||
logPath = "/var/log/secure"
|
||||
}
|
||||
filter = "sshd"
|
||||
port = tools.ExecShell("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
|
||||
port = 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.ExecShell("cat /www/server/mysql/conf/my.cnf | grep 'port' | head -n 1 | awk '{print $3}'")
|
||||
port = 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.ExecShell(`cat /www/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`)
|
||||
port = tools.Exec(`cat /www/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`)
|
||||
default:
|
||||
controllers.Error(ctx, http.StatusUnprocessableEntity, "未知服务")
|
||||
return
|
||||
@@ -335,10 +335,10 @@ logpath = ` + logPath + `
|
||||
# ` + jailName + `-END
|
||||
`
|
||||
raw += rule
|
||||
tools.WriteFile("/etc/fail2ban/jail.local", raw, 0644)
|
||||
tools.Write("/etc/fail2ban/jail.local", raw, 0644)
|
||||
}
|
||||
|
||||
tools.ExecShell("fail2ban-client reload")
|
||||
tools.Exec("fail2ban-client reload")
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ func (c *Fail2banController) Delete(ctx http.Context) {
|
||||
}
|
||||
|
||||
jailName := ctx.Request().Input("name")
|
||||
raw := tools.ReadFile("/etc/fail2ban/jail.local")
|
||||
raw := tools.Read("/etc/fail2ban/jail.local")
|
||||
if !strings.Contains(raw, "["+jailName+"]") {
|
||||
controllers.Error(ctx, http.StatusUnprocessableEntity, "规则不存在")
|
||||
return
|
||||
@@ -358,9 +358,9 @@ func (c *Fail2banController) Delete(ctx http.Context) {
|
||||
rule := tools.Cut(raw, "# "+jailName+"-START", "# "+jailName+"-END")
|
||||
raw = strings.Replace(raw, "\n# "+jailName+"-START"+rule+"# "+jailName+"-END", "", -1)
|
||||
raw = strings.TrimSpace(raw)
|
||||
tools.WriteFile("/etc/fail2ban/jail.local", raw, 0644)
|
||||
tools.Write("/etc/fail2ban/jail.local", raw, 0644)
|
||||
|
||||
tools.ExecShell("fail2ban-client reload")
|
||||
tools.Exec("fail2ban-client reload")
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -376,9 +376,9 @@ func (c *Fail2banController) BanList(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
currentlyBan := tools.ExecShell(`fail2ban-client status ` + name + ` | grep "Currently banned" | awk '{print $4}'`)
|
||||
totalBan := tools.ExecShell(`fail2ban-client status ` + name + ` | grep "Total banned" | awk '{print $4}'`)
|
||||
bannedIp := tools.ExecShell(`fail2ban-client status ` + name + ` | grep "Banned IP list" | awk -F ":" '{print $2}'`)
|
||||
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}'`)
|
||||
bannedIpList := strings.Split(bannedIp, " ")
|
||||
|
||||
var list []map[string]string
|
||||
@@ -411,7 +411,7 @@ func (c *Fail2banController) Unban(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("fail2ban-client set " + name + " unbanip " + ip)
|
||||
tools.Exec("fail2ban-client set " + name + " unbanip " + ip)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -427,7 +427,7 @@ func (c *Fail2banController) SetWhiteList(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
raw := tools.ReadFile("/etc/fail2ban/jail.local")
|
||||
raw := tools.Read("/etc/fail2ban/jail.local")
|
||||
// 正则替换
|
||||
reg := regexp.MustCompile(`ignoreip\s*=\s*.*\n`)
|
||||
if reg.MatchString(raw) {
|
||||
@@ -437,8 +437,8 @@ func (c *Fail2banController) SetWhiteList(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.WriteFile("/etc/fail2ban/jail.local", raw, 0644)
|
||||
tools.ExecShell("fail2ban-client reload")
|
||||
tools.Write("/etc/fail2ban/jail.local", raw, 0644)
|
||||
tools.Exec("fail2ban-client reload")
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -448,7 +448,7 @@ func (c *Fail2banController) GetWhiteList(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
raw := tools.ReadFile("/etc/fail2ban/jail.local")
|
||||
raw := tools.Read("/etc/fail2ban/jail.local")
|
||||
reg := regexp.MustCompile(`ignoreip\s*=\s*(.*)\n`)
|
||||
if reg.MatchString(raw) {
|
||||
ignoreIp := reg.FindStringSubmatch(raw)[1]
|
||||
|
||||
@@ -34,7 +34,7 @@ func (c *Mysql57Controller) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -53,8 +53,8 @@ func (c *Mysql57Controller) Reload(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl reload mysqld")
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl reload mysqld")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -73,8 +73,8 @@ func (c *Mysql57Controller) Restart(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl restart mysqld")
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl restart mysqld")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -93,8 +93,8 @@ func (c *Mysql57Controller) Start(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl start mysqld")
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl start mysqld")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -113,8 +113,8 @@ func (c *Mysql57Controller) Stop(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl stop mysqld")
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl stop mysqld")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -134,7 +134,7 @@ func (c *Mysql57Controller) GetConfig(ctx http.Context) {
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
config := tools.ReadFile("/www/server/mysql/conf/my.cnf")
|
||||
config := tools.Read("/www/server/mysql/conf/my.cnf")
|
||||
if len(config) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL配置失败")
|
||||
return
|
||||
@@ -155,12 +155,12 @@ func (c *Mysql57Controller) SaveConfig(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !tools.WriteFile("/www/server/mysql/conf/my.cnf", config, 0644) {
|
||||
if !tools.Write("/www/server/mysql/conf/my.cnf", config, 0644) {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "写入MySQL配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, "保存MySQL配置成功")
|
||||
c.Restart(ctx)
|
||||
}
|
||||
|
||||
// Load 获取负载
|
||||
@@ -175,13 +175,13 @@ func (c *Mysql57Controller) Load(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if status != "active" {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "MySQL 已停止运行")
|
||||
return
|
||||
}
|
||||
|
||||
raw := tools.ExecShell("/www/server/mysql/bin/mysqladmin -uroot -p" + rootPassword + " extended-status 2>&1")
|
||||
raw := tools.Exec("/www/server/mysql/bin/mysqladmin -uroot -p" + rootPassword + " extended-status 2>&1")
|
||||
if strings.Contains(raw, "Access denied for user") {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "MySQL root密码错误")
|
||||
return
|
||||
@@ -247,7 +247,7 @@ func (c *Mysql57Controller) ErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/mysql/mysql-error.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/mysql/mysql-error.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ func (c *Mysql57Controller) ClearErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/mysql/mysql-error.log")
|
||||
tools.Exec("echo '' > /www/server/mysql/mysql-error.log")
|
||||
controllers.Success(ctx, "清空错误日志成功")
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ func (c *Mysql57Controller) SlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/mysql/mysql-slow.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/mysql/mysql-slow.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ func (c *Mysql57Controller) ClearSlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/mysql/mysql-slow.log")
|
||||
tools.Exec("echo '' > /www/server/mysql/mysql-slow.log")
|
||||
controllers.Success(ctx, "清空慢查询日志成功")
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ func (c *Mysql57Controller) SetRootPassword(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -320,12 +320,12 @@ func (c *Mysql57Controller) SetRootPassword(ctx http.Context) {
|
||||
|
||||
oldRootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
if oldRootPassword != rootPassword {
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + rootPassword + "';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
err := c.setting.Set(models.SettingKeyMysqlRootPassword, rootPassword)
|
||||
if err != nil {
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + oldRootPassword + "';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "设置root密码失败")
|
||||
return
|
||||
}
|
||||
@@ -425,10 +425,10 @@ func (c *Mysql57Controller) AddDatabase(ctx http.Context) {
|
||||
user := ctx.Request().Input("user")
|
||||
password := ctx.Request().Input("password")
|
||||
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE DATABASE IF NOT EXISTS " + database + " DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
|
||||
controllers.Success(ctx, "添加数据库成功")
|
||||
}
|
||||
@@ -453,13 +453,17 @@ func (c *Mysql57Controller) DeleteDatabase(ctx http.Context) {
|
||||
|
||||
rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
database := ctx.Request().Input("database")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP DATABASE IF EXISTS " + database + ";\"")
|
||||
tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP DATABASE IF EXISTS " + database + ";\"")
|
||||
|
||||
controllers.Success(ctx, "删除数据库成功")
|
||||
}
|
||||
|
||||
// BackupList 获取备份列表
|
||||
func (c *Mysql57Controller) BackupList(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "mysql57") {
|
||||
return
|
||||
}
|
||||
|
||||
backupList, err := c.backup.MysqlList()
|
||||
if err != nil {
|
||||
facades.Log().Error("[MySQL57] 获取备份列表失败:" + err.Error())
|
||||
@@ -546,7 +550,7 @@ func (c *Mysql57Controller) DeleteBackup(ctx http.Context) {
|
||||
|
||||
backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/mysql"
|
||||
fileName := ctx.Request().Input("name")
|
||||
tools.RemoveFile(backupPath + "/" + fileName)
|
||||
tools.Remove(backupPath + "/" + fileName)
|
||||
|
||||
controllers.Success(ctx, "删除备份成功")
|
||||
}
|
||||
@@ -691,9 +695,9 @@ func (c *Mysql57Controller) AddUser(ctx http.Context) {
|
||||
user := ctx.Request().Input("user")
|
||||
password := ctx.Request().Input("password")
|
||||
database := ctx.Request().Input("database")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + ";'\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
|
||||
controllers.Success(ctx, "添加成功")
|
||||
}
|
||||
@@ -718,7 +722,7 @@ func (c *Mysql57Controller) DeleteUser(ctx http.Context) {
|
||||
|
||||
rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
user := ctx.Request().Input("user")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP USER '" + user + "'@'localhost';\"")
|
||||
tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP USER '" + user + "'@'localhost';\"")
|
||||
|
||||
controllers.Success(ctx, "删除成功")
|
||||
}
|
||||
@@ -745,8 +749,8 @@ func (c *Mysql57Controller) SetUserPassword(ctx http.Context) {
|
||||
rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
user := ctx.Request().Input("user")
|
||||
password := ctx.Request().Input("password")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
|
||||
controllers.Success(ctx, "修改成功")
|
||||
}
|
||||
@@ -773,9 +777,9 @@ func (c *Mysql57Controller) SetUserPrivileges(ctx http.Context) {
|
||||
rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
user := ctx.Request().Input("user")
|
||||
database := ctx.Request().Input("database")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"REVOKE ALL PRIVILEGES ON *.* FROM '" + user + "'@'localhost';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
|
||||
controllers.Success(ctx, "修改成功")
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func (c *Mysql80Controller) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -53,8 +53,8 @@ func (c *Mysql80Controller) Reload(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl reload mysqld")
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl reload mysqld")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -73,8 +73,8 @@ func (c *Mysql80Controller) Restart(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl restart mysqld")
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl restart mysqld")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -93,8 +93,8 @@ func (c *Mysql80Controller) Start(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl start mysqld")
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl start mysqld")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -113,8 +113,8 @@ func (c *Mysql80Controller) Stop(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl stop mysqld")
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl stop mysqld")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -134,7 +134,7 @@ func (c *Mysql80Controller) GetConfig(ctx http.Context) {
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
config := tools.ReadFile("/www/server/mysql/conf/my.cnf")
|
||||
config := tools.Read("/www/server/mysql/conf/my.cnf")
|
||||
if len(config) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL配置失败")
|
||||
return
|
||||
@@ -155,12 +155,12 @@ func (c *Mysql80Controller) SaveConfig(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !tools.WriteFile("/www/server/mysql/conf/my.cnf", config, 0644) {
|
||||
if !tools.Write("/www/server/mysql/conf/my.cnf", config, 0644) {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "写入MySQL配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, "保存MySQL配置成功")
|
||||
c.Restart(ctx)
|
||||
}
|
||||
|
||||
// Load 获取负载
|
||||
@@ -175,13 +175,13 @@ func (c *Mysql80Controller) Load(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if status != "active" {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "MySQL 已停止运行")
|
||||
return
|
||||
}
|
||||
|
||||
raw := tools.ExecShell("/www/server/mysql/bin/mysqladmin -uroot -p" + rootPassword + " extended-status 2>&1")
|
||||
raw := tools.Exec("/www/server/mysql/bin/mysqladmin -uroot -p" + rootPassword + " extended-status 2>&1")
|
||||
if strings.Contains(raw, "Access denied for user") {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "MySQL root密码错误")
|
||||
return
|
||||
@@ -247,7 +247,7 @@ func (c *Mysql80Controller) ErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/mysql/mysql-error.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/mysql/mysql-error.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ func (c *Mysql80Controller) ClearErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/mysql/mysql-error.log")
|
||||
tools.Exec("echo '' > /www/server/mysql/mysql-error.log")
|
||||
controllers.Success(ctx, "清空错误日志成功")
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ func (c *Mysql80Controller) SlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/mysql/mysql-slow.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/mysql/mysql-slow.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ func (c *Mysql80Controller) ClearSlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/mysql/mysql-slow.log")
|
||||
tools.Exec("echo '' > /www/server/mysql/mysql-slow.log")
|
||||
controllers.Success(ctx, "清空慢查询日志成功")
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ func (c *Mysql80Controller) SetRootPassword(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败")
|
||||
return
|
||||
@@ -320,12 +320,12 @@ func (c *Mysql80Controller) SetRootPassword(ctx http.Context) {
|
||||
|
||||
oldRootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
if oldRootPassword != rootPassword {
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + rootPassword + "';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + oldRootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
err := c.setting.Set(models.SettingKeyMysqlRootPassword, rootPassword)
|
||||
if err != nil {
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '" + oldRootPassword + "';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "设置root密码失败")
|
||||
return
|
||||
}
|
||||
@@ -425,10 +425,10 @@ func (c *Mysql80Controller) AddDatabase(ctx http.Context) {
|
||||
user := ctx.Request().Input("user")
|
||||
password := ctx.Request().Input("password")
|
||||
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE DATABASE IF NOT EXISTS " + database + " DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
|
||||
controllers.Success(ctx, "添加数据库成功")
|
||||
}
|
||||
@@ -453,13 +453,17 @@ func (c *Mysql80Controller) DeleteDatabase(ctx http.Context) {
|
||||
|
||||
rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
database := ctx.Request().Input("database")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP DATABASE IF EXISTS " + database + ";\"")
|
||||
tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP DATABASE IF EXISTS " + database + ";\"")
|
||||
|
||||
controllers.Success(ctx, "删除数据库成功")
|
||||
}
|
||||
|
||||
// BackupList 获取备份列表
|
||||
func (c *Mysql80Controller) BackupList(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "mysql80") {
|
||||
return
|
||||
}
|
||||
|
||||
backupList, err := c.backup.MysqlList()
|
||||
if err != nil {
|
||||
facades.Log().Error("[MySQL80] 获取备份列表失败:" + err.Error())
|
||||
@@ -546,7 +550,7 @@ func (c *Mysql80Controller) DeleteBackup(ctx http.Context) {
|
||||
|
||||
backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/mysql"
|
||||
fileName := ctx.Request().Input("name")
|
||||
tools.RemoveFile(backupPath + "/" + fileName)
|
||||
tools.Remove(backupPath + "/" + fileName)
|
||||
|
||||
controllers.Success(ctx, "删除备份成功")
|
||||
}
|
||||
@@ -691,9 +695,9 @@ func (c *Mysql80Controller) AddUser(ctx http.Context) {
|
||||
user := ctx.Request().Input("user")
|
||||
password := ctx.Request().Input("password")
|
||||
database := ctx.Request().Input("database")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"CREATE USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + ";'\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
|
||||
controllers.Success(ctx, "添加成功")
|
||||
}
|
||||
@@ -718,7 +722,7 @@ func (c *Mysql80Controller) DeleteUser(ctx http.Context) {
|
||||
|
||||
rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
user := ctx.Request().Input("user")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP USER '" + user + "'@'localhost';\"")
|
||||
tools.Exec("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"DROP USER '" + user + "'@'localhost';\"")
|
||||
|
||||
controllers.Success(ctx, "删除成功")
|
||||
}
|
||||
@@ -745,8 +749,8 @@ func (c *Mysql80Controller) SetUserPassword(ctx http.Context) {
|
||||
rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
user := ctx.Request().Input("user")
|
||||
password := ctx.Request().Input("password")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"ALTER USER '" + user + "'@'localhost' IDENTIFIED BY '" + password + "';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
|
||||
controllers.Success(ctx, "修改成功")
|
||||
}
|
||||
@@ -773,9 +777,9 @@ func (c *Mysql80Controller) SetUserPrivileges(ctx http.Context) {
|
||||
rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
user := ctx.Request().Input("user")
|
||||
database := ctx.Request().Input("database")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"REVOKE ALL PRIVILEGES ON *.* FROM '" + user + "'@'localhost';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"GRANT ALL PRIVILEGES ON " + database + ".* TO '" + user + "'@'localhost';\"")
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot -p" + rootPassword + " -e \"FLUSH PRIVILEGES;\"")
|
||||
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;\"")
|
||||
|
||||
controllers.Success(ctx, "修改成功")
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ func NewOpenrestyController() *OpenRestyController {
|
||||
}
|
||||
|
||||
// Status 获取运行状态
|
||||
func (r *OpenRestyController) Status(ctx http.Context) {
|
||||
func (c *OpenRestyController) Status(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty状态失败")
|
||||
return
|
||||
@@ -43,13 +43,13 @@ func (r *OpenRestyController) Status(ctx http.Context) {
|
||||
}
|
||||
|
||||
// Reload 重载配置
|
||||
func (r *OpenRestyController) Reload(ctx http.Context) {
|
||||
func (c *OpenRestyController) Reload(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl reload openresty")
|
||||
status := tools.ExecShell("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl reload openresty")
|
||||
status := tools.Exec("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty状态失败")
|
||||
return
|
||||
@@ -63,13 +63,13 @@ func (r *OpenRestyController) Reload(ctx http.Context) {
|
||||
}
|
||||
|
||||
// Start 启动OpenResty
|
||||
func (r *OpenRestyController) Start(ctx http.Context) {
|
||||
func (c *OpenRestyController) Start(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl start openresty")
|
||||
status := tools.ExecShell("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl start openresty")
|
||||
status := tools.Exec("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty状态失败")
|
||||
return
|
||||
@@ -83,13 +83,13 @@ func (r *OpenRestyController) Start(ctx http.Context) {
|
||||
}
|
||||
|
||||
// Stop 停止OpenResty
|
||||
func (r *OpenRestyController) Stop(ctx http.Context) {
|
||||
func (c *OpenRestyController) Stop(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl stop openresty")
|
||||
status := tools.ExecShell("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl stop openresty")
|
||||
status := tools.Exec("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty状态失败")
|
||||
return
|
||||
@@ -103,13 +103,13 @@ func (r *OpenRestyController) Stop(ctx http.Context) {
|
||||
}
|
||||
|
||||
// Restart 重启OpenResty
|
||||
func (r *OpenRestyController) Restart(ctx http.Context) {
|
||||
func (c *OpenRestyController) Restart(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl restart openresty")
|
||||
status := tools.ExecShell("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl restart openresty")
|
||||
status := tools.Exec("systemctl status openresty | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty状态失败")
|
||||
return
|
||||
@@ -123,12 +123,12 @@ func (r *OpenRestyController) Restart(ctx http.Context) {
|
||||
}
|
||||
|
||||
// GetConfig 获取配置
|
||||
func (r *OpenRestyController) GetConfig(ctx http.Context) {
|
||||
func (c *OpenRestyController) GetConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
|
||||
config := tools.ReadFile("/www/server/openresty/conf/nginx.conf")
|
||||
config := tools.Read("/www/server/openresty/conf/nginx.conf")
|
||||
if len(config) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty配置失败")
|
||||
return
|
||||
@@ -138,7 +138,7 @@ func (r *OpenRestyController) GetConfig(ctx http.Context) {
|
||||
}
|
||||
|
||||
// SaveConfig 保存配置
|
||||
func (r *OpenRestyController) SaveConfig(ctx http.Context) {
|
||||
func (c *OpenRestyController) SaveConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
@@ -149,16 +149,16 @@ func (r *OpenRestyController) SaveConfig(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !tools.WriteFile("/www/server/openresty/conf/nginx.conf", config, 0644) {
|
||||
if !tools.Write("/www/server/openresty/conf/nginx.conf", config, 0644) {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "保存OpenResty配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, "保存OpenResty配置成功")
|
||||
c.Reload(ctx)
|
||||
}
|
||||
|
||||
// ErrorLog 获取错误日志
|
||||
func (r *OpenRestyController) ErrorLog(ctx http.Context) {
|
||||
func (c *OpenRestyController) ErrorLog(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
@@ -168,22 +168,22 @@ func (r *OpenRestyController) ErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
out := tools.ExecShell("tail -n 100 /www/wwwlogs/nginx_error.log")
|
||||
out := tools.Exec("tail -n 100 /www/wwwlogs/nginx_error.log")
|
||||
controllers.Success(ctx, out)
|
||||
}
|
||||
|
||||
// ClearErrorLog 清空错误日志
|
||||
func (r *OpenRestyController) ClearErrorLog(ctx http.Context) {
|
||||
func (c *OpenRestyController) ClearErrorLog(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/wwwlogs/nginx_error.log")
|
||||
tools.Exec("echo '' > /www/wwwlogs/nginx_error.log")
|
||||
controllers.Success(ctx, "清空OpenResty错误日志成功")
|
||||
}
|
||||
|
||||
// Load 获取负载
|
||||
func (r *OpenRestyController) Load(ctx http.Context) {
|
||||
func (c *OpenRestyController) Load(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
@@ -203,13 +203,13 @@ func (r *OpenRestyController) Load(ctx http.Context) {
|
||||
}
|
||||
var data []nginxStatus
|
||||
|
||||
workers := tools.ExecShell("ps aux | grep nginx | grep 'worker process' | wc -l")
|
||||
workers := tools.Exec("ps aux | grep nginx | grep 'worker process' | wc -l")
|
||||
data = append(data, nginxStatus{
|
||||
Name: "工作进程",
|
||||
Value: workers,
|
||||
})
|
||||
|
||||
out := tools.ExecShell("ps aux | grep nginx | grep 'worker process' | awk '{memsum+=$6};END {print memsum}'")
|
||||
out := tools.Exec("ps aux | grep nginx | grep 'worker process' | awk '{memsum+=$6};END {print memsum}'")
|
||||
mem := tools.FormatBytes(cast.ToFloat64(out))
|
||||
data = append(data, nginxStatus{
|
||||
Name: "内存占用",
|
||||
|
||||
@@ -35,7 +35,7 @@ func (c *Php74Controller) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
return
|
||||
@@ -53,8 +53,8 @@ func (c *Php74Controller) Reload(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl reload php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl reload php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -73,8 +73,8 @@ func (c *Php74Controller) Start(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl start php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl start php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -93,8 +93,8 @@ func (c *Php74Controller) Stop(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl stop php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl stop php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -113,8 +113,8 @@ func (c *Php74Controller) Restart(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl restart php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl restart php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -133,7 +133,7 @@ func (c *Php74Controller) GetConfig(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
config := tools.ReadFile("/www/server/php/" + c.version + "/etc/php.ini")
|
||||
config := tools.Read("/www/server/php/" + c.version + "/etc/php.ini")
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func (c *Php74Controller) SaveConfig(ctx http.Context) {
|
||||
}
|
||||
|
||||
config := ctx.Request().Input("config")
|
||||
tools.WriteFile("/www/server/php/"+c.version+"/etc/php.ini", config, 0644)
|
||||
tools.Write("/www/server/php/"+c.version+"/etc/php.ini", config, 0644)
|
||||
c.Reload(ctx)
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ func (c *Php74Controller) ErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + c.version + "/var/log/php-fpm.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ func (c *Php74Controller) SlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + c.version + "/var/log/slow.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ func (c *Php74Controller) ClearErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
tools.Exec("echo '' > /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
controllers.Success(ctx, true)
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ func (c *Php74Controller) ClearSlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
tools.Exec("echo '' > /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
controllers.Success(ctx, true)
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func (c *Php74Controller) GetExtensions() []Extension {
|
||||
Installed: false,
|
||||
})
|
||||
|
||||
raw := tools.ExecShell("/www/server/php/" + c.version + "/bin/php -m")
|
||||
raw := tools.Exec("/www/server/php/" + c.version + "/bin/php -m")
|
||||
rawExtensionList := strings.Split(raw, "\n")
|
||||
|
||||
for _, item := range rawExtensionList {
|
||||
|
||||
@@ -35,7 +35,7 @@ func (c *Php80Controller) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
return
|
||||
@@ -53,8 +53,8 @@ func (c *Php80Controller) Reload(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl reload php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl reload php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -73,8 +73,8 @@ func (c *Php80Controller) Start(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl start php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl start php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -93,8 +93,8 @@ func (c *Php80Controller) Stop(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl stop php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl stop php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -113,8 +113,8 @@ func (c *Php80Controller) Restart(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl restart php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl restart php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -133,7 +133,7 @@ func (c *Php80Controller) GetConfig(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
config := tools.ReadFile("/www/server/php/" + c.version + "/etc/php.ini")
|
||||
config := tools.Read("/www/server/php/" + c.version + "/etc/php.ini")
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func (c *Php80Controller) SaveConfig(ctx http.Context) {
|
||||
}
|
||||
|
||||
config := ctx.Request().Input("config")
|
||||
tools.WriteFile("/www/server/php/"+c.version+"/etc/php.ini", config, 0644)
|
||||
tools.Write("/www/server/php/"+c.version+"/etc/php.ini", config, 0644)
|
||||
c.Reload(ctx)
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ func (c *Php80Controller) ErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + c.version + "/var/log/php-fpm.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ func (c *Php80Controller) SlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + c.version + "/var/log/slow.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ func (c *Php80Controller) ClearErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
tools.Exec("echo '' > /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
controllers.Success(ctx, true)
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ func (c *Php80Controller) ClearSlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
tools.Exec("echo '' > /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
controllers.Success(ctx, true)
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func (c *Php80Controller) GetExtensions() []Extension {
|
||||
Installed: false,
|
||||
})
|
||||
|
||||
raw := tools.ExecShell("/www/server/php/" + c.version + "/bin/php -m")
|
||||
raw := tools.Exec("/www/server/php/" + c.version + "/bin/php -m")
|
||||
rawExtensionList := strings.Split(raw, "\n")
|
||||
|
||||
for _, item := range rawExtensionList {
|
||||
|
||||
@@ -35,7 +35,7 @@ func (c *Php81Controller) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
return
|
||||
@@ -53,8 +53,8 @@ func (c *Php81Controller) Reload(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl reload php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl reload php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -73,8 +73,8 @@ func (c *Php81Controller) Start(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl start php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl start php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -93,8 +93,8 @@ func (c *Php81Controller) Stop(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl stop php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl stop php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -113,8 +113,8 @@ func (c *Php81Controller) Restart(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl restart php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl restart php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -133,7 +133,7 @@ func (c *Php81Controller) GetConfig(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
config := tools.ReadFile("/www/server/php/" + c.version + "/etc/php.ini")
|
||||
config := tools.Read("/www/server/php/" + c.version + "/etc/php.ini")
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func (c *Php81Controller) SaveConfig(ctx http.Context) {
|
||||
}
|
||||
|
||||
config := ctx.Request().Input("config")
|
||||
tools.WriteFile("/www/server/php/"+c.version+"/etc/php.ini", config, 0644)
|
||||
tools.Write("/www/server/php/"+c.version+"/etc/php.ini", config, 0644)
|
||||
c.Reload(ctx)
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ func (c *Php81Controller) ErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + c.version + "/var/log/php-fpm.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ func (c *Php81Controller) SlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + c.version + "/var/log/slow.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ func (c *Php81Controller) ClearErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
tools.Exec("echo '' > /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
controllers.Success(ctx, true)
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ func (c *Php81Controller) ClearSlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
tools.Exec("echo '' > /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
controllers.Success(ctx, true)
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func (c *Php81Controller) GetExtensions() []Extension {
|
||||
Installed: false,
|
||||
})
|
||||
|
||||
raw := tools.ExecShell("/www/server/php/" + c.version + "/bin/php -m")
|
||||
raw := tools.Exec("/www/server/php/" + c.version + "/bin/php -m")
|
||||
rawExtensionList := strings.Split(raw, "\n")
|
||||
|
||||
for _, item := range rawExtensionList {
|
||||
|
||||
@@ -35,7 +35,7 @@ func (c *Php82Controller) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
return
|
||||
@@ -53,8 +53,8 @@ func (c *Php82Controller) Reload(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl reload php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl reload php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -73,8 +73,8 @@ func (c *Php82Controller) Start(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl start php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl start php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -93,8 +93,8 @@ func (c *Php82Controller) Stop(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl stop php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl stop php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -113,8 +113,8 @@ func (c *Php82Controller) Restart(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl restart php-fpm-" + c.version)
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl restart php-fpm-" + c.version)
|
||||
out := tools.Exec("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
@@ -133,7 +133,7 @@ func (c *Php82Controller) GetConfig(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
config := tools.ReadFile("/www/server/php/" + c.version + "/etc/php.ini")
|
||||
config := tools.Read("/www/server/php/" + c.version + "/etc/php.ini")
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func (c *Php82Controller) SaveConfig(ctx http.Context) {
|
||||
}
|
||||
|
||||
config := ctx.Request().Input("config")
|
||||
tools.WriteFile("/www/server/php/"+c.version+"/etc/php.ini", config, 0644)
|
||||
tools.Write("/www/server/php/"+c.version+"/etc/php.ini", config, 0644)
|
||||
c.Reload(ctx)
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ func (c *Php82Controller) ErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + c.version + "/var/log/php-fpm.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ func (c *Php82Controller) SlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 100 /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
log := tools.Escape(tools.Exec("tail -n 100 /www/server/php/" + c.version + "/var/log/slow.log"))
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ func (c *Php82Controller) ClearErrorLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
tools.Exec("echo '' > /www/server/php/" + c.version + "/var/log/php-fpm.log")
|
||||
controllers.Success(ctx, true)
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ func (c *Php82Controller) ClearSlowLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("echo '' > /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
tools.Exec("echo '' > /www/server/php/" + c.version + "/var/log/slow.log")
|
||||
controllers.Success(ctx, true)
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ func (c *Php82Controller) GetExtensions() []Extension {
|
||||
Installed: false,
|
||||
})
|
||||
|
||||
raw := tools.ExecShell("/www/server/php/" + c.version + "/bin/php -m")
|
||||
raw := tools.Exec("/www/server/php/" + c.version + "/bin/php -m")
|
||||
rawExtensionList := strings.Split(raw, "\n")
|
||||
|
||||
for _, item := range rawExtensionList {
|
||||
|
||||
@@ -40,7 +40,7 @@ func (c *PhpMyAdminController) Info(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
conf := tools.ReadFile("/www/server/vhost/phpmyadmin.conf")
|
||||
conf := tools.Read("/www/server/vhost/phpmyadmin.conf")
|
||||
match := regexp.MustCompile(`listen\s+(\d+);`).FindStringSubmatch(conf)
|
||||
if len(match) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "找不到 phpMyAdmin 端口")
|
||||
@@ -64,18 +64,18 @@ func (c *PhpMyAdminController) SetPort(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
conf := tools.ReadFile("/www/server/vhost/phpmyadmin.conf")
|
||||
conf := tools.Read("/www/server/vhost/phpmyadmin.conf")
|
||||
conf = regexp.MustCompile(`listen\s+(\d+);`).ReplaceAllString(conf, "listen "+port+";")
|
||||
tools.WriteFile("/www/server/vhost/phpmyadmin.conf", conf, 0644)
|
||||
tools.Write("/www/server/vhost/phpmyadmin.conf", conf, 0644)
|
||||
|
||||
if tools.IsRHEL() {
|
||||
tools.ExecShell("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent")
|
||||
tools.ExecShell("firewall-cmd --reload")
|
||||
tools.Exec("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent")
|
||||
tools.Exec("firewall-cmd --reload")
|
||||
} else {
|
||||
tools.ExecShell("ufw allow " + port + "/tcp")
|
||||
tools.ExecShell("ufw reload")
|
||||
tools.Exec("ufw allow " + port + "/tcp")
|
||||
tools.Exec("ufw reload")
|
||||
}
|
||||
tools.ExecShell("systemctl reload openresty")
|
||||
tools.Exec("systemctl reload openresty")
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,624 @@
|
||||
package postgresql15
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/goravel/framework/support/carbon"
|
||||
|
||||
"panel/app/http/controllers"
|
||||
"panel/app/models"
|
||||
"panel/app/services"
|
||||
"panel/pkg/tools"
|
||||
)
|
||||
|
||||
type Postgresql15Controller struct {
|
||||
setting services.Setting
|
||||
backup services.Backup
|
||||
}
|
||||
|
||||
type Info struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
func NewPostgresql15Controller() *Postgresql15Controller {
|
||||
return &Postgresql15Controller{
|
||||
setting: services.NewSettingImpl(),
|
||||
backup: services.NewBackupImpl(),
|
||||
}
|
||||
}
|
||||
|
||||
// Status 获取运行状态
|
||||
func (c *Postgresql15Controller) Status(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败")
|
||||
return
|
||||
}
|
||||
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Reload 重载配置
|
||||
func (c *Postgresql15Controller) Reload(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("systemctl reload postgresql")
|
||||
status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败")
|
||||
return
|
||||
}
|
||||
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Restart 重启服务
|
||||
func (c *Postgresql15Controller) Restart(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("systemctl restart postgresql")
|
||||
status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败")
|
||||
return
|
||||
}
|
||||
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Start 启动服务
|
||||
func (c *Postgresql15Controller) Start(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("systemctl start postgresql")
|
||||
status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败")
|
||||
return
|
||||
}
|
||||
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop 停止服务
|
||||
func (c *Postgresql15Controller) Stop(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("systemctl stop postgresql")
|
||||
status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败")
|
||||
return
|
||||
}
|
||||
|
||||
if status != "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// GetConfig 获取配置
|
||||
func (c *Postgresql15Controller) GetConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
config := tools.Read("/www/server/postgresql/data/postgresql.conf")
|
||||
if len(config) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
// GetUserConfig 获取用户配置
|
||||
func (c *Postgresql15Controller) GetUserConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
config := tools.Read("/www/server/postgresql/data/pg_hba.conf")
|
||||
if len(config) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
// SaveConfig 保存配置
|
||||
func (c *Postgresql15Controller) SaveConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
config := ctx.Request().Input("config")
|
||||
if len(config) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "配置不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
if !tools.Write("/www/server/postgresql/data/postgresql.conf", config, 0644) {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "写入PostgreSQL配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
c.Restart(ctx)
|
||||
}
|
||||
|
||||
// SaveUserConfig 保存用户配置
|
||||
func (c *Postgresql15Controller) SaveUserConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
config := ctx.Request().Input("config")
|
||||
if len(config) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "配置不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
if !tools.Write("/www/server/postgresql/data/pg_hba.conf", config, 0644) {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "写入PostgreSQL配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
c.Restart(ctx)
|
||||
}
|
||||
|
||||
// Load 获取负载
|
||||
func (c *Postgresql15Controller) Load(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if status != "active" {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL 已停止运行")
|
||||
return
|
||||
}
|
||||
|
||||
data := []Info{
|
||||
{"启动时间", 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`)},
|
||||
}
|
||||
|
||||
controllers.Success(ctx, data)
|
||||
}
|
||||
|
||||
// Log 获取日志
|
||||
func (c *Postgresql15Controller) Log(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.Exec("tail -n 100 /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log")
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
// ClearLog 清空日志
|
||||
func (c *Postgresql15Controller) ClearLog(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("echo '' > /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log")
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// DatabaseList 获取数据库列表
|
||||
func (c *Postgresql15Controller) DatabaseList(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.Exec("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if status != "active" {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL 已停止运行")
|
||||
return
|
||||
}
|
||||
|
||||
raw := tools.Exec(`echo "\l" | su - postgres -c "psql"`)
|
||||
databases := strings.Split(raw, "\n")
|
||||
databases = databases[3 : len(databases)-1]
|
||||
|
||||
type database struct {
|
||||
Name string `json:"name"`
|
||||
Owner string `json:"owner"`
|
||||
Encoding string `json:"encoding"`
|
||||
}
|
||||
|
||||
var databaseList []database
|
||||
for _, db := range databases {
|
||||
parts := strings.Split(db, "|")
|
||||
if len(parts) != 8 || len(strings.TrimSpace(parts[0])) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
databaseList = append(databaseList, database{
|
||||
Name: strings.TrimSpace(parts[0]),
|
||||
Owner: strings.TrimSpace(parts[1]),
|
||||
Encoding: strings.TrimSpace(parts[2]),
|
||||
})
|
||||
}
|
||||
|
||||
page := ctx.Request().QueryInt("page", 1)
|
||||
limit := ctx.Request().QueryInt("limit", 10)
|
||||
startIndex := (page - 1) * limit
|
||||
endIndex := page * limit
|
||||
if startIndex > len(databaseList) {
|
||||
controllers.Success(ctx, http.Json{
|
||||
"total": 0,
|
||||
"items": []database{},
|
||||
})
|
||||
return
|
||||
}
|
||||
if endIndex > len(databaseList) {
|
||||
endIndex = len(databaseList)
|
||||
}
|
||||
pagedDatabases := databaseList[startIndex:endIndex]
|
||||
|
||||
controllers.Success(ctx, http.Json{
|
||||
"total": len(databaseList),
|
||||
"items": pagedDatabases,
|
||||
})
|
||||
}
|
||||
|
||||
// AddDatabase 添加数据库
|
||||
func (c *Postgresql15Controller) AddDatabase(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
validator, err := ctx.Request().Validate(map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:255",
|
||||
})
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if validator.Fails() {
|
||||
controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One())
|
||||
return
|
||||
}
|
||||
|
||||
database := ctx.Request().Input("database")
|
||||
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 "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`)
|
||||
|
||||
userConfig := "host " + database + " " + user + " 127.0.0.1/32 scram-sha-256"
|
||||
tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`)
|
||||
|
||||
c.Reload(ctx)
|
||||
}
|
||||
|
||||
// DeleteDatabase 删除数据库
|
||||
func (c *Postgresql15Controller) DeleteDatabase(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
validator, err := ctx.Request().Validate(map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:postgres,template0,template1",
|
||||
})
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if validator.Fails() {
|
||||
controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One())
|
||||
return
|
||||
}
|
||||
|
||||
database := ctx.Request().Input("database")
|
||||
tools.Exec(`echo "DROP DATABASE ` + database + `;" | su - postgres -c "psql"`)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// BackupList 获取备份列表
|
||||
func (c *Postgresql15Controller) BackupList(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
backupList, err := c.backup.PostgresqlList()
|
||||
if err != nil {
|
||||
facades.Log().Error("[PostgreSQL] 获取备份列表失败:" + err.Error())
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取备份列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, backupList)
|
||||
}
|
||||
|
||||
// UploadBackup 上传备份
|
||||
func (c *Postgresql15Controller) UploadBackup(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
file, err := ctx.Request().File("file")
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "上传文件失败")
|
||||
return
|
||||
}
|
||||
|
||||
backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/postgresql"
|
||||
if !tools.Exists(backupPath) {
|
||||
tools.Mkdir(backupPath, 0644)
|
||||
}
|
||||
|
||||
name := file.GetClientOriginalName()
|
||||
_, err = file.StoreAs(backupPath, name)
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "上传文件失败")
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// CreateBackup 创建备份
|
||||
func (c *Postgresql15Controller) CreateBackup(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
validator, err := ctx.Request().Validate(map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys",
|
||||
})
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if validator.Fails() {
|
||||
controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One())
|
||||
return
|
||||
}
|
||||
|
||||
database := ctx.Request().Input("database")
|
||||
err = c.backup.PostgresqlBackup(database)
|
||||
if err != nil {
|
||||
facades.Log().Error("[PostgreSQL] 创建备份失败:" + err.Error())
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "创建备份失败")
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// DeleteBackup 删除备份
|
||||
func (c *Postgresql15Controller) DeleteBackup(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
validator, err := ctx.Request().Validate(map[string]string{
|
||||
"name": "required|min_len:1|max_len:255",
|
||||
})
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if validator.Fails() {
|
||||
controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One())
|
||||
return
|
||||
}
|
||||
|
||||
backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/postgresql"
|
||||
fileName := ctx.Request().Input("name")
|
||||
tools.Remove(backupPath + "/" + fileName)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// RestoreBackup 还原备份
|
||||
func (c *Postgresql15Controller) RestoreBackup(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
validator, err := ctx.Request().Validate(map[string]string{
|
||||
"name": "required|min_len:1|max_len:255",
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys",
|
||||
})
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if validator.Fails() {
|
||||
controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One())
|
||||
return
|
||||
}
|
||||
|
||||
err = c.backup.PostgresqlRestore(ctx.Request().Input("database"), ctx.Request().Input("name"))
|
||||
if err != nil {
|
||||
facades.Log().Error("[PostgreSQL] 还原失败:" + err.Error())
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "还原失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// UserList 用户列表
|
||||
func (c *Postgresql15Controller) UserList(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
type user struct {
|
||||
User string `json:"user"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
raw := tools.Exec(`echo "\du" | su - postgres -c "psql"`)
|
||||
users := strings.Split(raw, "\n")
|
||||
if len(users) < 4 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "用户列表为空")
|
||||
return
|
||||
}
|
||||
users = users[3:]
|
||||
|
||||
var userList []user
|
||||
for _, u := range users {
|
||||
userInfo := strings.Split(u, "|")
|
||||
if len(userInfo) != 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
userList = append(userList, user{
|
||||
User: strings.TrimSpace(userInfo[0]),
|
||||
Role: strings.TrimSpace(userInfo[1]),
|
||||
})
|
||||
}
|
||||
|
||||
page := ctx.Request().QueryInt("page", 1)
|
||||
limit := ctx.Request().QueryInt("limit", 10)
|
||||
startIndex := (page - 1) * limit
|
||||
endIndex := page * limit
|
||||
if startIndex > len(userList) {
|
||||
controllers.Success(ctx, http.Json{
|
||||
"total": 0,
|
||||
"items": []user{},
|
||||
})
|
||||
return
|
||||
}
|
||||
if endIndex > len(userList) {
|
||||
endIndex = len(userList)
|
||||
}
|
||||
pagedUsers := userList[startIndex:endIndex]
|
||||
|
||||
controllers.Success(ctx, http.Json{
|
||||
"total": len(userList),
|
||||
"items": pagedUsers,
|
||||
})
|
||||
}
|
||||
|
||||
// AddUser 添加用户
|
||||
func (c *Postgresql15Controller) AddUser(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
validator, err := ctx.Request().Validate(map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:255",
|
||||
})
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if validator.Fails() {
|
||||
controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One())
|
||||
return
|
||||
}
|
||||
|
||||
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"`)
|
||||
|
||||
userConfig := "host " + database + " " + user + " 127.0.0.1/32 scram-sha-256"
|
||||
tools.Exec(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`)
|
||||
|
||||
c.Reload(ctx)
|
||||
}
|
||||
|
||||
// DeleteUser 删除用户
|
||||
func (c *Postgresql15Controller) DeleteUser(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
validator, err := ctx.Request().Validate(map[string]string{
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
})
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if validator.Fails() {
|
||||
controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One())
|
||||
return
|
||||
}
|
||||
|
||||
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`)
|
||||
|
||||
c.Reload(ctx)
|
||||
}
|
||||
|
||||
// SetUserPassword 设置用户密码
|
||||
func (c *Postgresql15Controller) SetUserPassword(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "postgresql15") {
|
||||
return
|
||||
}
|
||||
|
||||
validator, err := ctx.Request().Validate(map[string]string{
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:255",
|
||||
})
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if validator.Fails() {
|
||||
controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One())
|
||||
return
|
||||
}
|
||||
|
||||
user := ctx.Request().Input("user")
|
||||
password := ctx.Request().Input("password")
|
||||
tools.Exec(`echo "ALTER USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
@@ -28,7 +28,7 @@ func (c *PureFtpdController) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := tools.Exec("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd状态失败")
|
||||
return
|
||||
@@ -47,8 +47,8 @@ func (c *PureFtpdController) Reload(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl reload pure-ftpd")
|
||||
status := tools.ExecShell("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'")
|
||||
tools.Exec("systemctl reload pure-ftpd")
|
||||
status := tools.Exec("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd状态失败")
|
||||
return
|
||||
@@ -67,8 +67,8 @@ func (c *PureFtpdController) Restart(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl restart pure-ftpd")
|
||||
status := tools.ExecShell("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'")
|
||||
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 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd状态失败")
|
||||
return
|
||||
@@ -87,8 +87,8 @@ func (c *PureFtpdController) Start(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl start pure-ftpd")
|
||||
status := tools.ExecShell("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'")
|
||||
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 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd状态失败")
|
||||
return
|
||||
@@ -107,8 +107,8 @@ func (c *PureFtpdController) Stop(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell("systemctl stop pure-ftpd")
|
||||
status := tools.ExecShell("systemctl status pure-ftpd | grep Active | grep -v grep | awk '{print $2}'")
|
||||
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 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd状态失败")
|
||||
return
|
||||
@@ -127,7 +127,7 @@ func (c *PureFtpdController) List(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
listRaw := tools.ExecShell("pure-pw list")
|
||||
listRaw := tools.Exec("pure-pw list")
|
||||
if len(listRaw) == 0 {
|
||||
controllers.Success(ctx, http.Json{
|
||||
"total": 0,
|
||||
@@ -204,10 +204,10 @@ func (c *PureFtpdController) Add(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.Chmod(path, 755)
|
||||
tools.Chmod(path, 0755)
|
||||
tools.Chown(path, "www", "www")
|
||||
tools.ExecShell(`yes '` + password + `' | pure-pw useradd ` + username + ` -u www -g www -d ` + path)
|
||||
tools.ExecShell("pure-pw mkdb")
|
||||
tools.Exec(`yes '` + password + `' | pure-pw useradd ` + username + ` -u www -g www -d ` + path)
|
||||
tools.Exec("pure-pw mkdb")
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
@@ -232,8 +232,8 @@ func (c *PureFtpdController) Delete(ctx http.Context) {
|
||||
|
||||
username := ctx.Request().Input("username")
|
||||
|
||||
tools.ExecShell("pure-pw userdel " + username + " -m")
|
||||
tools.ExecShell("pure-pw mkdb")
|
||||
tools.Exec("pure-pw userdel " + username + " -m")
|
||||
tools.Exec("pure-pw mkdb")
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
@@ -260,8 +260,8 @@ func (c *PureFtpdController) ChangePassword(ctx http.Context) {
|
||||
username := ctx.Request().Input("username")
|
||||
password := ctx.Request().Input("password")
|
||||
|
||||
tools.ExecShell(`yes '` + password + `' | pure-pw passwd ` + username + ` -m`)
|
||||
tools.ExecShell("pure-pw mkdb")
|
||||
tools.Exec(`yes '` + password + `' | pure-pw passwd ` + username + ` -m`)
|
||||
tools.Exec("pure-pw mkdb")
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
@@ -272,7 +272,7 @@ func (c *PureFtpdController) GetPort(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
port := tools.ExecShell(`cat /www/server/pure-ftpd/etc/pure-ftpd.conf | grep "Bind" | awk '{print $2}' | awk -F "," '{print $2}'`)
|
||||
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 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PureFtpd端口失败")
|
||||
return
|
||||
@@ -300,15 +300,15 @@ func (c *PureFtpdController) SetPort(ctx http.Context) {
|
||||
}
|
||||
|
||||
port := ctx.Request().Input("port")
|
||||
tools.ExecShell(`sed -i "s/Bind.*/Bind 0.0.0.0,` + port + `/g" /www/server/pure-ftpd/etc/pure-ftpd.conf`)
|
||||
tools.Exec(`sed -i "s/Bind.*/Bind 0.0.0.0,` + port + `/g" /www/server/pure-ftpd/etc/pure-ftpd.conf`)
|
||||
if tools.IsRHEL() {
|
||||
tools.ExecShell("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent")
|
||||
tools.ExecShell("firewall-cmd --reload")
|
||||
tools.Exec("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent")
|
||||
tools.Exec("firewall-cmd --reload")
|
||||
} else {
|
||||
tools.ExecShell("ufw allow " + port + "/tcp")
|
||||
tools.ExecShell("ufw reload")
|
||||
tools.Exec("ufw allow " + port + "/tcp")
|
||||
tools.Exec("ufw reload")
|
||||
}
|
||||
tools.ExecShell("systemctl restart pure-ftpd")
|
||||
tools.Exec("systemctl restart pure-ftpd")
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
|
||||
"panel/app/http/controllers"
|
||||
"panel/pkg/tools"
|
||||
)
|
||||
|
||||
type RedisController struct {
|
||||
}
|
||||
|
||||
type Info struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
func NewRedisController() *RedisController {
|
||||
return &RedisController{}
|
||||
}
|
||||
|
||||
// Status 获取运行状态
|
||||
func (c *RedisController) Status(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "redis") {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败")
|
||||
return
|
||||
}
|
||||
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Reload 重载配置
|
||||
func (c *RedisController) Reload(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "redis") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("systemctl reload redis")
|
||||
status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败")
|
||||
return
|
||||
}
|
||||
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Restart 重启服务
|
||||
func (c *RedisController) Restart(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "redis") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("systemctl restart redis")
|
||||
status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败")
|
||||
return
|
||||
}
|
||||
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Start 启动服务
|
||||
func (c *RedisController) Start(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "redis") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("systemctl start redis")
|
||||
status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败")
|
||||
return
|
||||
}
|
||||
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop 停止服务
|
||||
func (c *RedisController) Stop(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "redis") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("systemctl stop redis")
|
||||
status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取Redis状态失败")
|
||||
return
|
||||
}
|
||||
|
||||
if status != "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// GetConfig 获取配置
|
||||
func (c *RedisController) GetConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "redis") {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
config := tools.Read("/www/server/redis/redis.conf")
|
||||
if len(config) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取Redis配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
// SaveConfig 保存配置
|
||||
func (c *RedisController) SaveConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "redis") {
|
||||
return
|
||||
}
|
||||
|
||||
config := ctx.Request().Input("config")
|
||||
if len(config) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "配置不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
if !tools.Write("/www/server/redis/redis.conf", config, 0644) {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "写入Redis配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
c.Restart(ctx)
|
||||
}
|
||||
|
||||
// Load 获取负载
|
||||
func (c *RedisController) Load(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "redis") {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.Exec("systemctl status redis | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if status != "active" {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "Redis 已停止运行")
|
||||
return
|
||||
}
|
||||
|
||||
raw := tools.Exec("redis-cli info")
|
||||
if len(raw) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取Redis负载失败")
|
||||
return
|
||||
}
|
||||
|
||||
infoLines := strings.Split(raw, "\n")
|
||||
dataRaw := make(map[string]string)
|
||||
|
||||
for _, item := range infoLines {
|
||||
parts := strings.Split(item, ":")
|
||||
if len(parts) == 2 {
|
||||
dataRaw[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
|
||||
data := []Info{
|
||||
{"TCP 端口", dataRaw["tcp_port"]},
|
||||
{"已运行天数", dataRaw["uptime_in_days"]},
|
||||
{"连接的客户端数", dataRaw["connected_clients"]},
|
||||
{"已分配的内存总量", dataRaw["used_memory_human"]},
|
||||
{"占用内存总量", dataRaw["used_memory_rss_human"]},
|
||||
{"占用内存峰值", dataRaw["used_memory_peak_human"]},
|
||||
{"内存碎片比率", dataRaw["mem_fragmentation_ratio"]},
|
||||
{"运行以来连接过的客户端的总数", dataRaw["total_connections_received"]},
|
||||
{"运行以来执行过的命令的总数", dataRaw["total_commands_processed"]},
|
||||
{"每秒执行的命令数", dataRaw["instantaneous_ops_per_sec"]},
|
||||
{"查找数据库键成功次数", dataRaw["keyspace_hits"]},
|
||||
{"查找数据库键失败次数", dataRaw["keyspace_misses"]},
|
||||
{"最近一次 fork() 操作耗费的毫秒数", dataRaw["latest_fork_usec"]},
|
||||
}
|
||||
|
||||
controllers.Success(ctx, data)
|
||||
}
|
||||
@@ -125,17 +125,17 @@ func (c *S3fsController) Add(ctx http.Context) {
|
||||
|
||||
id := carbon.Now().TimestampMilli()
|
||||
password := ak + ":" + sk
|
||||
tools.WriteFile("/etc/passwd-s3fs-"+cast.ToString(id), password, 0600)
|
||||
tools.ExecShell(`echo 's3fs#` + bucket + ` ` + path + ` fuse _netdev,allow_other,nonempty,url=` + url + `,passwd_file=/etc/passwd-s3fs-` + cast.ToString(id) + ` 0 0' >> /etc/fstab`)
|
||||
check := tools.ExecShell("mount -a 2>&1")
|
||||
tools.Write("/etc/passwd-s3fs-"+cast.ToString(id), password, 0600)
|
||||
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`)
|
||||
check := tools.Exec("mount -a 2>&1")
|
||||
if len(check) != 0 {
|
||||
tools.ExecShell(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`)
|
||||
tools.Exec(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`)
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "检测到/etc/fstab有误: "+check)
|
||||
return
|
||||
}
|
||||
check2 := tools.ExecShell("df -h | grep " + path + " 2>&1")
|
||||
check2 := tools.Exec("df -h | grep " + path + " 2>&1")
|
||||
if len(check2) == 0 {
|
||||
tools.ExecShell(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`)
|
||||
tools.Exec(`sed -i 's@^s3fs#` + bucket + `\s` + path + `.*$@@g' /etc/fstab`)
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "挂载失败,请检查配置是否正确")
|
||||
return
|
||||
}
|
||||
@@ -191,15 +191,15 @@ func (c *S3fsController) Delete(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`fusermount -u '` + mount.Path + `' 2>&1`)
|
||||
tools.ExecShell(`umount '` + mount.Path + `' 2>&1`)
|
||||
tools.ExecShell(`sed -i 's@^s3fs#` + mount.Bucket + `\s` + mount.Path + `.*$@@g' /etc/fstab`)
|
||||
check := tools.ExecShell("mount -a 2>&1")
|
||||
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`)
|
||||
check := tools.Exec("mount -a 2>&1")
|
||||
if len(check) != 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "检测到/etc/fstab有误: "+check)
|
||||
return
|
||||
}
|
||||
tools.RemoveFile("/etc/passwd-s3fs-" + cast.ToString(mount.ID))
|
||||
tools.Remove("/etc/passwd-s3fs-" + cast.ToString(mount.ID))
|
||||
|
||||
var newS3fsList []s3fs
|
||||
for _, s := range s3fsList {
|
||||
|
||||
@@ -28,12 +28,12 @@ func NewSupervisorController() *SupervisorController {
|
||||
}
|
||||
|
||||
// Status 状态
|
||||
func (r *SupervisorController) Status(ctx http.Context) {
|
||||
func (c *SupervisorController) Status(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
status := tools.Exec(`systemctl status ` + c.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
@@ -42,13 +42,13 @@ func (r *SupervisorController) Status(ctx http.Context) {
|
||||
}
|
||||
|
||||
// Start 启动
|
||||
func (r *SupervisorController) Start(ctx http.Context) {
|
||||
func (c *SupervisorController) Start(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`systemctl start ` + r.ServiceName)
|
||||
status := tools.ExecShell(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
tools.Exec(`systemctl start ` + c.ServiceName)
|
||||
status := tools.Exec(`systemctl status ` + c.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
@@ -57,13 +57,13 @@ func (r *SupervisorController) Start(ctx http.Context) {
|
||||
}
|
||||
|
||||
// Stop 停止
|
||||
func (r *SupervisorController) Stop(ctx http.Context) {
|
||||
func (c *SupervisorController) Stop(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`systemctl stop ` + r.ServiceName)
|
||||
status := tools.ExecShell(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
tools.Exec(`systemctl stop ` + c.ServiceName)
|
||||
status := tools.Exec(`systemctl status ` + c.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
if status != "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
@@ -72,13 +72,13 @@ func (r *SupervisorController) Stop(ctx http.Context) {
|
||||
}
|
||||
|
||||
// Restart 重启
|
||||
func (r *SupervisorController) Restart(ctx http.Context) {
|
||||
func (c *SupervisorController) Restart(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`systemctl restart ` + r.ServiceName)
|
||||
status := tools.ExecShell(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
tools.Exec(`systemctl restart ` + c.ServiceName)
|
||||
status := tools.Exec(`systemctl status ` + c.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
@@ -87,13 +87,13 @@ func (r *SupervisorController) Restart(ctx http.Context) {
|
||||
}
|
||||
|
||||
// Reload 重载
|
||||
func (r *SupervisorController) Reload(ctx http.Context) {
|
||||
func (c *SupervisorController) Reload(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`systemctl reload ` + r.ServiceName)
|
||||
status := tools.ExecShell(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
tools.Exec(`systemctl reload ` + c.ServiceName)
|
||||
status := tools.Exec(`systemctl status ` + c.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
@@ -102,59 +102,58 @@ func (r *SupervisorController) Reload(ctx http.Context) {
|
||||
}
|
||||
|
||||
// Log 日志
|
||||
func (r *SupervisorController) Log(ctx http.Context) {
|
||||
func (c *SupervisorController) Log(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell(`tail -n 200 /var/log/supervisor/supervisord.log`)
|
||||
log := tools.Exec(`tail -n 200 /var/log/supervisor/supervisord.log`)
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
// ClearLog 清空日志
|
||||
func (r *SupervisorController) ClearLog(ctx http.Context) {
|
||||
func (c *SupervisorController) ClearLog(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`echo "" > /var/log/supervisor/supervisord.log`)
|
||||
tools.Exec(`echo "" > /var/log/supervisor/supervisord.log`)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// Config 获取配置
|
||||
func (r *SupervisorController) Config(ctx http.Context) {
|
||||
func (c *SupervisorController) Config(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
var config string
|
||||
if tools.IsRHEL() {
|
||||
config = tools.ReadFile(`/etc/supervisord.conf`)
|
||||
config = tools.Read(`/etc/supervisord.conf`)
|
||||
} else {
|
||||
config = tools.ReadFile(`/etc/supervisor/supervisord.conf`)
|
||||
config = tools.Read(`/etc/supervisor/supervisord.conf`)
|
||||
}
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
// SaveConfig 保存配置
|
||||
func (r *SupervisorController) SaveConfig(ctx http.Context) {
|
||||
func (c *SupervisorController) SaveConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
config := ctx.Request().Input("config")
|
||||
if tools.IsRHEL() {
|
||||
tools.WriteFile(`/etc/supervisord.conf`, config, 0644)
|
||||
tools.Write(`/etc/supervisord.conf`, config, 0644)
|
||||
} else {
|
||||
tools.WriteFile(`/etc/supervisor/supervisord.conf`, config, 0644)
|
||||
tools.Write(`/etc/supervisor/supervisord.conf`, config, 0644)
|
||||
}
|
||||
|
||||
tools.ExecShell(`systemctl restart ` + r.ServiceName)
|
||||
controllers.Success(ctx, nil)
|
||||
c.Restart(ctx)
|
||||
}
|
||||
|
||||
// Processes 进程列表
|
||||
func (r *SupervisorController) Processes(ctx http.Context) {
|
||||
func (c *SupervisorController) Processes(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
@@ -169,7 +168,7 @@ func (r *SupervisorController) Processes(ctx http.Context) {
|
||||
Uptime string `json:"uptime"`
|
||||
}
|
||||
|
||||
out := tools.ExecShell(`supervisorctl status | awk '{print $1}'`)
|
||||
out := tools.Exec(`supervisorctl status | awk '{print $1}'`)
|
||||
var processList []process
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
if len(line) == 0 {
|
||||
@@ -178,10 +177,10 @@ func (r *SupervisorController) Processes(ctx http.Context) {
|
||||
|
||||
var p process
|
||||
p.Name = line
|
||||
p.Status = tools.ExecShell(`supervisorctl status ` + line + ` | awk '{print $2}'`)
|
||||
p.Status = tools.Exec(`supervisorctl status ` + line + ` | awk '{print $2}'`)
|
||||
if p.Status == "RUNNING" {
|
||||
p.Pid = strings.ReplaceAll(tools.ExecShell(`supervisorctl status `+line+` | awk '{print $4}'`), ",", "")
|
||||
p.Uptime = tools.ExecShell(`supervisorctl status ` + line + ` | awk '{print $6}'`)
|
||||
p.Pid = strings.ReplaceAll(tools.Exec(`supervisorctl status `+line+` | awk '{print $4}'`), ",", "")
|
||||
p.Uptime = tools.Exec(`supervisorctl status ` + line + ` | awk '{print $6}'`)
|
||||
} else {
|
||||
p.Pid = "-"
|
||||
p.Uptime = "-"
|
||||
@@ -210,40 +209,40 @@ func (r *SupervisorController) Processes(ctx http.Context) {
|
||||
}
|
||||
|
||||
// StartProcess 启动进程
|
||||
func (r *SupervisorController) StartProcess(ctx http.Context) {
|
||||
func (c *SupervisorController) StartProcess(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
tools.ExecShell(`supervisorctl start ` + process)
|
||||
tools.Exec(`supervisorctl start ` + process)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// StopProcess 停止进程
|
||||
func (r *SupervisorController) StopProcess(ctx http.Context) {
|
||||
func (c *SupervisorController) StopProcess(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
tools.ExecShell(`supervisorctl stop ` + process)
|
||||
tools.Exec(`supervisorctl stop ` + process)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// RestartProcess 重启进程
|
||||
func (r *SupervisorController) RestartProcess(ctx http.Context) {
|
||||
func (c *SupervisorController) RestartProcess(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
tools.ExecShell(`supervisorctl restart ` + process)
|
||||
tools.Exec(`supervisorctl restart ` + process)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// ProcessLog 进程日志
|
||||
func (r *SupervisorController) ProcessLog(ctx http.Context) {
|
||||
func (c *SupervisorController) ProcessLog(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
@@ -251,17 +250,17 @@ func (r *SupervisorController) ProcessLog(ctx http.Context) {
|
||||
process := ctx.Request().Input("process")
|
||||
var logPath string
|
||||
if tools.IsRHEL() {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
logPath = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
} else {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
logPath = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
}
|
||||
|
||||
log := tools.ExecShell(`tail -n 200 ` + logPath)
|
||||
log := tools.Exec(`tail -n 200 ` + logPath)
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
// ClearProcessLog 清空进程日志
|
||||
func (r *SupervisorController) ClearProcessLog(ctx http.Context) {
|
||||
func (c *SupervisorController) ClearProcessLog(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
@@ -269,17 +268,17 @@ func (r *SupervisorController) ClearProcessLog(ctx http.Context) {
|
||||
process := ctx.Request().Input("process")
|
||||
var logPath string
|
||||
if tools.IsRHEL() {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
logPath = tools.Exec(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
} else {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
logPath = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
}
|
||||
|
||||
tools.ExecShell(`echo "" > ` + logPath)
|
||||
tools.Exec(`echo "" > ` + logPath)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// ProcessConfig 获取进程配置
|
||||
func (r *SupervisorController) ProcessConfig(ctx http.Context) {
|
||||
func (c *SupervisorController) ProcessConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
@@ -287,16 +286,16 @@ func (r *SupervisorController) ProcessConfig(ctx http.Context) {
|
||||
process := ctx.Request().Query("process")
|
||||
var config string
|
||||
if tools.IsRHEL() {
|
||||
config = tools.ReadFile(`/etc/supervisord.d/` + process + `.conf`)
|
||||
config = tools.Read(`/etc/supervisord.d/` + process + `.conf`)
|
||||
} else {
|
||||
config = tools.ReadFile(`/etc/supervisor/conf.d/` + process + `.conf`)
|
||||
config = tools.Read(`/etc/supervisor/conf.d/` + process + `.conf`)
|
||||
}
|
||||
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
// SaveProcessConfig 保存进程配置
|
||||
func (r *SupervisorController) SaveProcessConfig(ctx http.Context) {
|
||||
func (c *SupervisorController) SaveProcessConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
@@ -304,19 +303,19 @@ func (r *SupervisorController) SaveProcessConfig(ctx http.Context) {
|
||||
process := ctx.Request().Input("process")
|
||||
config := ctx.Request().Input("config")
|
||||
if tools.IsRHEL() {
|
||||
tools.WriteFile(`/etc/supervisord.d/`+process+`.conf`, config, 0644)
|
||||
tools.Write(`/etc/supervisord.d/`+process+`.conf`, config, 0644)
|
||||
} else {
|
||||
tools.WriteFile(`/etc/supervisor/conf.d/`+process+`.conf`, config, 0644)
|
||||
tools.Write(`/etc/supervisor/conf.d/`+process+`.conf`, config, 0644)
|
||||
}
|
||||
tools.ExecShell(`supervisorctl reread`)
|
||||
tools.ExecShell(`supervisorctl update`)
|
||||
tools.ExecShell(`supervisorctl start ` + process)
|
||||
tools.Exec(`supervisorctl reread`)
|
||||
tools.Exec(`supervisorctl update`)
|
||||
tools.Exec(`supervisorctl start ` + process)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// AddProcess 添加进程
|
||||
func (r *SupervisorController) AddProcess(ctx http.Context) {
|
||||
func (c *SupervisorController) AddProcess(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
@@ -355,36 +354,36 @@ stdout_logfile=/var/log/supervisor/` + name + `.log
|
||||
stdout_logfile_maxbytes=2MB
|
||||
`
|
||||
if tools.IsRHEL() {
|
||||
tools.WriteFile(`/etc/supervisord.d/`+name+`.conf`, config, 0644)
|
||||
tools.Write(`/etc/supervisord.d/`+name+`.conf`, config, 0644)
|
||||
} else {
|
||||
tools.WriteFile(`/etc/supervisor/conf.d/`+name+`.conf`, config, 0644)
|
||||
tools.Write(`/etc/supervisor/conf.d/`+name+`.conf`, config, 0644)
|
||||
}
|
||||
tools.ExecShell(`supervisorctl reread`)
|
||||
tools.ExecShell(`supervisorctl update`)
|
||||
tools.ExecShell(`supervisorctl start ` + name)
|
||||
tools.Exec(`supervisorctl reread`)
|
||||
tools.Exec(`supervisorctl update`)
|
||||
tools.Exec(`supervisorctl start ` + name)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// DeleteProcess 删除进程
|
||||
func (r *SupervisorController) DeleteProcess(ctx http.Context) {
|
||||
func (c *SupervisorController) DeleteProcess(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
tools.ExecShell(`supervisorctl stop ` + process)
|
||||
tools.Exec(`supervisorctl stop ` + process)
|
||||
var logPath string
|
||||
if tools.IsRHEL() {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
tools.RemoveFile(`/etc/supervisord.d/` + process + `.conf`)
|
||||
logPath = 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.ExecShell(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
tools.RemoveFile(`/etc/supervisor/conf.d/` + process + `.conf`)
|
||||
logPath = tools.Exec(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
tools.Remove(`/etc/supervisor/conf.d/` + process + `.conf`)
|
||||
}
|
||||
tools.RemoveFile(logPath)
|
||||
tools.ExecShell(`supervisorctl reread`)
|
||||
tools.ExecShell(`supervisorctl update`)
|
||||
tools.Remove(logPath)
|
||||
tools.Exec(`supervisorctl reread`)
|
||||
tools.Exec(`supervisorctl update`)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
package toolbox
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/spf13/cast"
|
||||
|
||||
"panel/app/http/controllers"
|
||||
"panel/pkg/tools"
|
||||
)
|
||||
|
||||
type ToolBoxController struct {
|
||||
}
|
||||
|
||||
func NewToolBoxController() *ToolBoxController {
|
||||
return &ToolBoxController{}
|
||||
}
|
||||
|
||||
// GetDNS 获取 DNS 信息
|
||||
func (c *ToolBoxController) GetDNS(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "toolbox") {
|
||||
return
|
||||
}
|
||||
|
||||
raw := tools.Read("/etc/resolv.conf")
|
||||
match := regexp.MustCompile(`nameserver\s+(\S+)`).FindAllStringSubmatch(raw, -1)
|
||||
if len(match) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "找不到 DNS 信息")
|
||||
return
|
||||
}
|
||||
|
||||
var dns []string
|
||||
for _, m := range match {
|
||||
dns = append(dns, m[1])
|
||||
}
|
||||
|
||||
controllers.Success(ctx, dns)
|
||||
}
|
||||
|
||||
// SetDNS 设置 DNS 信息
|
||||
func (c *ToolBoxController) SetDNS(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "toolbox") {
|
||||
return
|
||||
}
|
||||
|
||||
dns1 := ctx.Request().Input("dns1")
|
||||
dns2 := ctx.Request().Input("dns2")
|
||||
|
||||
if len(dns1) == 0 || len(dns2) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "DNS 信息不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var dns string
|
||||
dns += "nameserver " + dns1 + "\n"
|
||||
dns += "nameserver " + dns2 + "\n"
|
||||
|
||||
tools.Write("/etc/resolv.conf", dns, 0644)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// GetSWAP 获取 SWAP 信息
|
||||
func (c *ToolBoxController) GetSWAP(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "toolbox") {
|
||||
return
|
||||
}
|
||||
|
||||
var total, size, used, free string
|
||||
if tools.Exists("/www/swap") {
|
||||
s, _ := tools.FileSize("/www/swap")
|
||||
size = strconv.Itoa(int(s / 1024 / 1024))
|
||||
total = tools.FormatBytes(float64(s))
|
||||
} else {
|
||||
size = "0.00 B"
|
||||
total = "0.00 B"
|
||||
}
|
||||
|
||||
raw := tools.Exec("LC_ALL=C free | grep 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)
|
||||
free = tools.FormatBytes(cast.ToFloat64(match[3]) * 1024)
|
||||
}
|
||||
|
||||
controllers.Success(ctx, http.Json{
|
||||
"total": total,
|
||||
"size": size,
|
||||
"used": used,
|
||||
"free": free,
|
||||
})
|
||||
}
|
||||
|
||||
// SetSWAP 设置 SWAP 信息
|
||||
func (c *ToolBoxController) SetSWAP(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "toolbox") {
|
||||
return
|
||||
}
|
||||
|
||||
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 size > 1 {
|
||||
free := tools.Exec("df -k /www | awk '{print $4}' | tail -n 1")
|
||||
if cast.ToInt64(free) < int64(size)*1024*1024 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "磁盘空间不足,当前剩余 "+tools.FormatBytes(cast.ToFloat64(free)))
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("dd if=/dev/zero of=/www/swap bs=1M count=" + cast.ToString(size))
|
||||
tools.Exec("mkswap -f /www/swap")
|
||||
tools.Exec("swapon /www/swap")
|
||||
tools.Exec("echo '/www/swap swap swap defaults 0 0' >> /etc/fstab")
|
||||
}
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// GetTimezone 获取时区
|
||||
func (c *ToolBoxController) GetTimezone(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "toolbox") {
|
||||
return
|
||||
}
|
||||
|
||||
raw := tools.Exec("LC_ALL=C timedatectl | grep zone")
|
||||
match := regexp.MustCompile(`zone:\s+(\S+)`).FindStringSubmatch(raw)
|
||||
if len(match) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "找不到时区信息")
|
||||
return
|
||||
}
|
||||
|
||||
zonesRaw := tools.Exec("LC_ALL=C timedatectl list-timezones")
|
||||
zones := strings.Split(zonesRaw, "\n")
|
||||
|
||||
controllers.Success(ctx, http.Json{
|
||||
"zone": match[1],
|
||||
"zones": zones,
|
||||
})
|
||||
}
|
||||
|
||||
// SetTimezone 设置时区
|
||||
func (c *ToolBoxController) SetTimezone(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "toolbox") {
|
||||
return
|
||||
}
|
||||
|
||||
timezone := ctx.Request().Input("timezone")
|
||||
if len(timezone) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "时区不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
tools.Exec("timedatectl set-timezone " + timezone)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// GetHosts 获取 hosts 信息
|
||||
func (c *ToolBoxController) GetHosts(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "toolbox") {
|
||||
return
|
||||
}
|
||||
|
||||
controllers.Success(ctx, tools.Read("/etc/hosts"))
|
||||
}
|
||||
|
||||
// SetHosts 设置 hosts 信息
|
||||
func (c *ToolBoxController) SetHosts(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "toolbox") {
|
||||
return
|
||||
}
|
||||
|
||||
hosts := ctx.Request().Input("hosts")
|
||||
if len(hosts) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "hosts 信息不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
tools.Write("/etc/hosts", hosts, 0644)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// SetRootPassword 设置 root 密码
|
||||
func (c *ToolBoxController) SetRootPassword(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "toolbox") {
|
||||
return
|
||||
}
|
||||
|
||||
password := ctx.Request().Input("password")
|
||||
if len(password) == 0 {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "密码不能为空")
|
||||
return
|
||||
}
|
||||
if !regexp.MustCompile(`^[a-zA-Z0-9·~!@#$%^&*()_+-=\[\]{};:'",./<>?]{6,20}$`).MatchString(password) {
|
||||
controllers.Error(ctx, http.StatusBadRequest, "密码必须为 6-20 位字母、数字或特殊字符")
|
||||
return
|
||||
}
|
||||
|
||||
password = strings.ReplaceAll(password, `'`, `\'`)
|
||||
tools.Exec(`yes '` + password + `' | passwd root`)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
@@ -28,15 +28,15 @@ func (r *SafeController) SetFirewallStatus(ctx http.Context) {
|
||||
var out string
|
||||
if ctx.Request().InputBool("status") {
|
||||
if tools.IsRHEL() {
|
||||
out = tools.ExecShell("systemctl start firewalld")
|
||||
out = tools.Exec("systemctl start firewalld")
|
||||
} else {
|
||||
out = tools.ExecShell("echo y | ufw enable")
|
||||
out = tools.Exec("echo y | ufw enable")
|
||||
}
|
||||
} else {
|
||||
if tools.IsRHEL() {
|
||||
out = tools.ExecShell("systemctl stop firewalld")
|
||||
out = tools.Exec("systemctl stop firewalld")
|
||||
} else {
|
||||
out = tools.ExecShell("ufw disable")
|
||||
out = tools.Exec("ufw disable")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,10 +52,13 @@ func (r *SafeController) GetFirewallRules(ctx http.Context) {
|
||||
limit := ctx.Request().QueryInt("limit", 10)
|
||||
|
||||
if tools.IsRHEL() {
|
||||
out := tools.ExecShell("firewall-cmd --list-all 2>&1")
|
||||
out := tools.Exec("firewall-cmd --list-all 2>&1")
|
||||
match := regexp.MustCompile(`ports: (.*)`).FindStringSubmatch(out)
|
||||
if len(match) == 0 {
|
||||
Success(ctx, nil)
|
||||
Success(ctx, http.Json{
|
||||
"total": 0,
|
||||
"items": []map[string]string{},
|
||||
})
|
||||
return
|
||||
}
|
||||
ports := strings.Split(match[1], " ")
|
||||
@@ -87,9 +90,12 @@ func (r *SafeController) GetFirewallRules(ctx http.Context) {
|
||||
"items": pagedRules,
|
||||
})
|
||||
} else {
|
||||
out := tools.ExecShell("ufw status | grep -v '(v6)' | grep ALLOW | awk '{print $1}'")
|
||||
out := tools.Exec("ufw status | grep -v '(v6)' | grep ALLOW | awk '{print $1}'")
|
||||
if len(out) == 0 {
|
||||
Success(ctx, nil)
|
||||
Success(ctx, http.Json{
|
||||
"total": 0,
|
||||
"items": []map[string]string{},
|
||||
})
|
||||
return
|
||||
}
|
||||
var rules []map[string]string
|
||||
@@ -136,13 +142,13 @@ func (r *SafeController) AddFirewallRule(ctx http.Context) {
|
||||
}
|
||||
|
||||
if tools.IsRHEL() {
|
||||
tools.ExecShell("firewall-cmd --remove-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1")
|
||||
tools.ExecShell("firewall-cmd --add-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1")
|
||||
tools.ExecShell("firewall-cmd --reload")
|
||||
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")
|
||||
} else {
|
||||
tools.ExecShell("ufw delete allow " + cast.ToString(port) + "/" + protocol)
|
||||
tools.ExecShell("ufw allow " + cast.ToString(port) + "/" + protocol)
|
||||
tools.ExecShell("ufw reload")
|
||||
tools.Exec("ufw delete allow " + cast.ToString(port) + "/" + protocol)
|
||||
tools.Exec("ufw allow " + cast.ToString(port) + "/" + protocol)
|
||||
tools.Exec("ufw reload")
|
||||
}
|
||||
|
||||
Success(ctx, nil)
|
||||
@@ -162,11 +168,11 @@ func (r *SafeController) DeleteFirewallRule(ctx http.Context) {
|
||||
}
|
||||
|
||||
if tools.IsRHEL() {
|
||||
tools.ExecShell("firewall-cmd --remove-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1")
|
||||
tools.ExecShell("firewall-cmd --reload")
|
||||
tools.Exec("firewall-cmd --remove-port=" + cast.ToString(port) + "/" + protocol + " --permanent 2>&1")
|
||||
tools.Exec("firewall-cmd --reload")
|
||||
} else {
|
||||
tools.ExecShell("ufw delete allow " + cast.ToString(port) + "/" + protocol)
|
||||
tools.ExecShell("ufw reload")
|
||||
tools.Exec("ufw delete allow " + cast.ToString(port) + "/" + protocol)
|
||||
tools.Exec("ufw reload")
|
||||
}
|
||||
|
||||
Success(ctx, nil)
|
||||
@@ -176,14 +182,14 @@ func (r *SafeController) firewallStatus() bool {
|
||||
var out string
|
||||
var running bool
|
||||
if tools.IsRHEL() {
|
||||
out = tools.ExecShell("systemctl status firewalld | grep Active | awk '{print $3}'")
|
||||
out = tools.Exec("systemctl status firewalld | grep Active | awk '{print $3}'")
|
||||
if out == "(running)" {
|
||||
running = true
|
||||
} else {
|
||||
running = false
|
||||
}
|
||||
} else {
|
||||
out = tools.ExecShell("ufw status | grep Status | awk '{print $2}'")
|
||||
out = tools.Exec("ufw status | grep Status | awk '{print $2}'")
|
||||
if out == "active" {
|
||||
running = true
|
||||
} else {
|
||||
@@ -197,9 +203,9 @@ func (r *SafeController) firewallStatus() bool {
|
||||
func (r *SafeController) GetSshStatus(ctx http.Context) {
|
||||
var out string
|
||||
if tools.IsRHEL() {
|
||||
out = tools.ExecShell("systemctl status sshd | grep Active | awk '{print $3}'")
|
||||
out = tools.Exec("systemctl status sshd | grep Active | awk '{print $3}'")
|
||||
} else {
|
||||
out = tools.ExecShell("systemctl status ssh | grep Active | awk '{print $3}'")
|
||||
out = tools.Exec("systemctl status ssh | grep Active | awk '{print $3}'")
|
||||
}
|
||||
|
||||
running := false
|
||||
@@ -213,19 +219,19 @@ func (r *SafeController) GetSshStatus(ctx http.Context) {
|
||||
func (r *SafeController) SetSshStatus(ctx http.Context) {
|
||||
if ctx.Request().InputBool("status") {
|
||||
if tools.IsRHEL() {
|
||||
tools.ExecShell("systemctl enable sshd")
|
||||
tools.ExecShell("systemctl start sshd")
|
||||
tools.Exec("systemctl enable sshd")
|
||||
tools.Exec("systemctl start sshd")
|
||||
} else {
|
||||
tools.ExecShell("systemctl enable ssh")
|
||||
tools.ExecShell("systemctl start ssh")
|
||||
tools.Exec("systemctl enable ssh")
|
||||
tools.Exec("systemctl start ssh")
|
||||
}
|
||||
} else {
|
||||
if tools.IsRHEL() {
|
||||
tools.ExecShell("systemctl stop sshd")
|
||||
tools.ExecShell("systemctl disable sshd")
|
||||
tools.Exec("systemctl stop sshd")
|
||||
tools.Exec("systemctl disable sshd")
|
||||
} else {
|
||||
tools.ExecShell("systemctl stop ssh")
|
||||
tools.ExecShell("systemctl disable ssh")
|
||||
tools.Exec("systemctl stop ssh")
|
||||
tools.Exec("systemctl disable ssh")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +239,7 @@ func (r *SafeController) SetSshStatus(ctx http.Context) {
|
||||
}
|
||||
|
||||
func (r *SafeController) GetSshPort(ctx http.Context) {
|
||||
out := tools.ExecShell("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
|
||||
out := tools.Exec("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
|
||||
Success(ctx, out)
|
||||
}
|
||||
|
||||
@@ -244,12 +250,12 @@ func (r *SafeController) SetSshPort(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
oldPort := tools.ExecShell("cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}'")
|
||||
tools.ExecShell("sed -i 's/#Port " + oldPort + "/Port " + cast.ToString(port) + "/g' /etc/ssh/sshd_config")
|
||||
tools.ExecShell("sed -i 's/Port " + oldPort + "/Port " + cast.ToString(port) + "/g' /etc/ssh/sshd_config")
|
||||
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")
|
||||
|
||||
if status := tools.ExecShell("systemctl status sshd | grep Active | awk '{print $3}'"); status == "(running)" {
|
||||
tools.ExecShell("systemctl restart sshd")
|
||||
if status := tools.Exec("systemctl status sshd | grep Active | awk '{print $3}'"); status == "(running)" {
|
||||
tools.Exec("systemctl restart sshd")
|
||||
}
|
||||
|
||||
Success(ctx, nil)
|
||||
@@ -257,14 +263,14 @@ func (r *SafeController) SetSshPort(ctx http.Context) {
|
||||
|
||||
func (r *SafeController) GetPingStatus(ctx http.Context) {
|
||||
if tools.IsRHEL() {
|
||||
out := tools.ExecShell(`firewall-cmd --list-all 2>&1`)
|
||||
out := tools.Exec(`firewall-cmd --list-all 2>&1`)
|
||||
if !strings.Contains(out, `rule protocol value="icmp" drop`) {
|
||||
Success(ctx, true)
|
||||
} else {
|
||||
Success(ctx, false)
|
||||
}
|
||||
} else {
|
||||
config := tools.ReadFile("/etc/ufw/before.rules")
|
||||
config := tools.Read("/etc/ufw/before.rules")
|
||||
if strings.Contains(config, "-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT") {
|
||||
Success(ctx, true)
|
||||
} else {
|
||||
@@ -276,18 +282,18 @@ func (r *SafeController) GetPingStatus(ctx http.Context) {
|
||||
func (r *SafeController) SetPingStatus(ctx http.Context) {
|
||||
if tools.IsRHEL() {
|
||||
if ctx.Request().InputBool("status") {
|
||||
tools.ExecShell(`firewall-cmd --permanent --remove-rich-rule='rule protocol value=icmp drop'`)
|
||||
tools.Exec(`firewall-cmd --permanent --remove-rich-rule='rule protocol value=icmp drop'`)
|
||||
} else {
|
||||
tools.ExecShell(`firewall-cmd --permanent --add-rich-rule='rule protocol value=icmp drop'`)
|
||||
tools.Exec(`firewall-cmd --permanent --add-rich-rule='rule protocol value=icmp drop'`)
|
||||
}
|
||||
tools.ExecShell(`firewall-cmd --reload`)
|
||||
tools.Exec(`firewall-cmd --reload`)
|
||||
} else {
|
||||
if ctx.Request().InputBool("status") {
|
||||
tools.ExecShell(`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`)
|
||||
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.ExecShell(`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(`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.ExecShell(`ufw reload`)
|
||||
tools.Exec(`ufw reload`)
|
||||
}
|
||||
|
||||
Success(ctx, nil)
|
||||
|
||||
@@ -49,7 +49,7 @@ func (r *SettingController) List(ctx http.Context) {
|
||||
result["username"] = user.Username
|
||||
result["email"] = user.Email
|
||||
|
||||
result["port"] = tools.ExecShell(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
|
||||
result["port"] = tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
|
||||
|
||||
Success(ctx, result)
|
||||
}
|
||||
@@ -71,9 +71,9 @@ func (r *SettingController) Save(ctx http.Context) {
|
||||
|
||||
return
|
||||
}
|
||||
oldPort := tools.ExecShell(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
|
||||
oldPort := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
|
||||
if oldPort != port {
|
||||
tools.ExecShell("sed -i 's/APP_PORT=" + oldPort + "/APP_PORT=" + port + "/g' /www/panel/panel.conf")
|
||||
tools.Exec("sed -i 's/APP_PORT=" + oldPort + "/APP_PORT=" + port + "/g' /www/panel/panel.conf")
|
||||
}
|
||||
if !tools.Exists(backupPath) {
|
||||
tools.Mkdir(backupPath, 0644)
|
||||
|
||||
@@ -62,7 +62,7 @@ func (r *TaskController) Log(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell("tail -n 30 " + task.Log)
|
||||
log := tools.Exec("tail -n 30 " + task.Log)
|
||||
|
||||
Success(ctx, log)
|
||||
}
|
||||
|
||||
@@ -111,8 +111,8 @@ func (c *WebsiteController) GetDefaultConfig(ctx http.Context) {
|
||||
if !Check(ctx, "openresty") {
|
||||
return
|
||||
}
|
||||
index := tools.ReadFile("/www/server/openresty/html/index.html")
|
||||
stop := tools.ReadFile("/www/server/openresty/html/stop.html")
|
||||
index := tools.Read("/www/server/openresty/html/index.html")
|
||||
stop := tools.Read("/www/server/openresty/html/stop.html")
|
||||
|
||||
Success(ctx, http.Json{
|
||||
"index": index,
|
||||
@@ -128,13 +128,13 @@ func (c *WebsiteController) SaveDefaultConfig(ctx http.Context) {
|
||||
index := ctx.Request().Input("index")
|
||||
stop := ctx.Request().Input("stop")
|
||||
|
||||
if !tools.WriteFile("/www/server/openresty/html/index.html", index, 0644) {
|
||||
if !tools.Write("/www/server/openresty/html/index.html", index, 0644) {
|
||||
facades.Log().Error("[面板][WebsiteController] 保存默认配置失败")
|
||||
Error(ctx, http.StatusInternalServerError, "系统内部错误")
|
||||
return
|
||||
}
|
||||
|
||||
if !tools.WriteFile("/www/server/openresty/html/stop.html", stop, 0644) {
|
||||
if !tools.Write("/www/server/openresty/html/stop.html", stop, 0644) {
|
||||
facades.Log().Error("[面板][WebsiteController] 保存默认配置失败")
|
||||
Error(ctx, http.StatusInternalServerError, "系统内部错误")
|
||||
return
|
||||
@@ -210,9 +210,10 @@ func (c *WebsiteController) SaveConfig(ctx http.Context) {
|
||||
}
|
||||
|
||||
// 原文
|
||||
raw := tools.ReadFile("/www/server/vhost/" + website.Name + ".conf")
|
||||
raw := tools.Read("/www/server/vhost/" + website.Name + ".conf")
|
||||
if strings.TrimSpace(raw) != strings.TrimSpace(ctx.Request().Input("raw")) {
|
||||
tools.WriteFile("/www/server/vhost/"+website.Name+".conf", ctx.Request().Input("raw"), 0644)
|
||||
tools.Write("/www/server/vhost/"+website.Name+".conf", ctx.Request().Input("raw"), 0644)
|
||||
tools.Exec("systemctl reload openresty")
|
||||
Success(ctx, nil)
|
||||
return
|
||||
}
|
||||
@@ -308,10 +309,10 @@ func (c *WebsiteController) SaveConfig(ctx http.Context) {
|
||||
root += "/"
|
||||
}
|
||||
if ctx.Request().InputBool("open_basedir") {
|
||||
tools.WriteFile(root+".user.ini", "open_basedir="+path+":/tmp/", 0644)
|
||||
tools.Write(root+".user.ini", "open_basedir="+path+":/tmp/", 0644)
|
||||
} else {
|
||||
if tools.Exists(root + ".user.ini") {
|
||||
tools.RemoveFile(root + ".user.ini")
|
||||
tools.Remove(root + ".user.ini")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,8 +337,8 @@ func (c *WebsiteController) SaveConfig(ctx http.Context) {
|
||||
// SSL
|
||||
ssl := ctx.Request().InputBool("ssl")
|
||||
website.Ssl = ssl
|
||||
tools.WriteFile("/www/server/vhost/ssl/"+website.Name+".pem", ctx.Request().Input("ssl_certificate"), 0644)
|
||||
tools.WriteFile("/www/server/vhost/ssl/"+website.Name+".key", ctx.Request().Input("ssl_certificate_key"), 0644)
|
||||
tools.Write("/www/server/vhost/ssl/"+website.Name+".pem", ctx.Request().Input("ssl_certificate"), 0644)
|
||||
tools.Write("/www/server/vhost/ssl/"+website.Name+".key", ctx.Request().Input("ssl_certificate_key"), 0644)
|
||||
if ssl {
|
||||
sslConfig := `# ssl标记位开始
|
||||
ssl_certificate /www/server/vhost/ssl/` + website.Name + `.pem;
|
||||
@@ -394,9 +395,9 @@ func (c *WebsiteController) SaveConfig(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.WriteFile("/www/server/vhost/"+website.Name+".conf", raw, 0644)
|
||||
tools.WriteFile("/www/server/vhost/rewrite/"+website.Name+".conf", ctx.Request().Input("rewrite"), 0644)
|
||||
tools.ExecShell("systemctl reload openresty")
|
||||
tools.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644)
|
||||
tools.Write("/www/server/vhost/rewrite/"+website.Name+".conf", ctx.Request().Input("rewrite"), 0644)
|
||||
tools.Exec("systemctl reload openresty")
|
||||
|
||||
Success(ctx, nil)
|
||||
}
|
||||
@@ -420,7 +421,7 @@ func (c *WebsiteController) ClearLog(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
tools.RemoveFile("/www/wwwlogs/" + website.Name + ".log")
|
||||
tools.Remove("/www/wwwlogs/" + website.Name + ".log")
|
||||
|
||||
Success(ctx, nil)
|
||||
}
|
||||
@@ -557,7 +558,7 @@ func (c *WebsiteController) DeleteBackup(ctx http.Context) {
|
||||
tools.Mkdir(backupPath, 0644)
|
||||
}
|
||||
|
||||
if !tools.RemoveFile(backupPath + "/" + fileName) {
|
||||
if !tools.Remove(backupPath + "/" + fileName) {
|
||||
Error(ctx, http.StatusInternalServerError, "删除备份失败")
|
||||
return
|
||||
}
|
||||
@@ -650,9 +651,9 @@ server
|
||||
|
||||
`, website.Path, website.Php, website.Name, website.Name, website.Name)
|
||||
|
||||
tools.WriteFile("/www/server/vhost/"+website.Name+".conf", raw, 0644)
|
||||
tools.WriteFile("/www/server/vhost/rewrite"+website.Name+".conf", "", 0644)
|
||||
tools.ExecShell("systemctl reload openresty")
|
||||
tools.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644)
|
||||
tools.Write("/www/server/vhost/rewrite"+website.Name+".conf", "", 0644)
|
||||
tools.Exec("systemctl reload openresty")
|
||||
|
||||
Success(ctx, nil)
|
||||
}
|
||||
@@ -682,7 +683,7 @@ func (c *WebsiteController) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
raw := tools.ReadFile("/www/server/vhost/" + website.Name + ".conf")
|
||||
raw := tools.Read("/www/server/vhost/" + website.Name + ".conf")
|
||||
|
||||
// 运行目录
|
||||
rootConfig := tools.Cut(raw, "# root标记位开始\n", "# root标记位结束")
|
||||
@@ -708,8 +709,8 @@ func (c *WebsiteController) Status(ctx http.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
tools.WriteFile("/www/server/vhost/"+website.Name+".conf", raw, 0644)
|
||||
tools.ExecShell("systemctl reload openresty")
|
||||
tools.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644)
|
||||
tools.Exec("systemctl reload openresty")
|
||||
|
||||
Success(ctx, nil)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import "github.com/goravel/framework/support/carbon"
|
||||
|
||||
const (
|
||||
SettingKeyName = "name"
|
||||
SettingKeyVersion = "version"
|
||||
SettingKeyMonitor = "monitor"
|
||||
SettingKeyMonitorDays = "monitor_days"
|
||||
SettingKeyBackupPath = "backup_path"
|
||||
|
||||
@@ -4,7 +4,7 @@ var (
|
||||
Name = "OpenResty"
|
||||
Description = "OpenResty® 是一款基于 NGINX 和 LuaJIT 的 Web 平台。"
|
||||
Slug = "openresty"
|
||||
Version = "1.21.4.1"
|
||||
Version = "1.21.4.2"
|
||||
Requires = []string{}
|
||||
Excludes = []string{}
|
||||
Install = "bash /www/panel/scripts/openresty/install.sh"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package postgresql15
|
||||
|
||||
var (
|
||||
Name = "PostgreSQL-15"
|
||||
Description = "PostgreSQL 是开源的对象 - 关系数据库数据库管理系统,在类似 BSD 许可与 MIT 许可的 PostgreSQL 许可下发行。"
|
||||
Slug = "postgresql15"
|
||||
Version = "15.3"
|
||||
Requires = []string{}
|
||||
Excludes = []string{}
|
||||
Install = `bash /www/panel/scripts/postgresql/install.sh 15`
|
||||
Uninstall = `bash /www/panel/scripts/postgresql/uninstall.sh 15`
|
||||
Update = `bash /www/panel/scripts/postgresql/update.sh 15`
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package redis
|
||||
|
||||
var (
|
||||
Name = "Redis"
|
||||
Description = "Redis 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。"
|
||||
Slug = "redis"
|
||||
Version = "7.0.12"
|
||||
Requires = []string{}
|
||||
Excludes = []string{}
|
||||
Install = `bash /www/panel/scripts/redis/install.sh`
|
||||
Uninstall = `bash /www/panel/scripts/redis/uninstall.sh`
|
||||
Update = `bash /www/panel/scripts/redis/update.sh`
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package toolbox
|
||||
|
||||
var (
|
||||
Name = "系统工具箱"
|
||||
Description = "可视化调整一些常用的配置项,如 DNS、SWAP、时区 等"
|
||||
Slug = "toolbox"
|
||||
Version = "1.0"
|
||||
Requires = []string{}
|
||||
Excludes = []string{}
|
||||
Install = `panel writePlugin toolbox 1.0`
|
||||
Uninstall = `panel deletePlugin toolbox`
|
||||
Update = `panel writePlugin toolbox 1.0`
|
||||
)
|
||||
+105
-13
@@ -20,6 +20,9 @@ type Backup interface {
|
||||
MysqlList() ([]BackupFile, error)
|
||||
MysqlBackup(database string) error
|
||||
MysqlRestore(database string, backupFile string) error
|
||||
PostgresqlList() ([]BackupFile, error)
|
||||
PostgresqlBackup(database string) error
|
||||
PostgresqlRestore(database string, backupFile string) error
|
||||
}
|
||||
|
||||
type BackupFile struct {
|
||||
@@ -81,7 +84,7 @@ func (s *BackupImpl) WebSiteBackup(website models.Website) error {
|
||||
}
|
||||
|
||||
backupFile := backupPath + "/" + website.Name + "_" + carbon.Now().ToShortDateTimeString() + ".zip"
|
||||
tools.ExecShell(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`)
|
||||
tools.Exec(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -103,8 +106,8 @@ func (s *BackupImpl) WebsiteRestore(website models.Website, backupFile string) e
|
||||
return errors.New("备份文件不存在")
|
||||
}
|
||||
|
||||
tools.ExecShell(`rm -rf '` + website.Path + `/*'`)
|
||||
tools.ExecShell(`unzip -o '` + backupFile + `' -d '` + website.Path + `' 2>&1`)
|
||||
tools.Exec(`rm -rf '` + website.Path + `/*'`)
|
||||
tools.Exec(`unzip -o '` + backupFile + `' -d '` + website.Path + `' 2>&1`)
|
||||
tools.Chmod(website.Path, 0755)
|
||||
tools.Chown(website.Path, "www", "www")
|
||||
|
||||
@@ -155,9 +158,9 @@ func (s *BackupImpl) MysqlBackup(database string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
tools.ExecShell("/www/server/mysql/bin/mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile)
|
||||
tools.ExecShell("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile)
|
||||
tools.RemoveFile(backupPath + "/" + backupFile)
|
||||
tools.Exec("/www/server/mysql/bin/mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile)
|
||||
tools.Exec("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile)
|
||||
tools.Remove(backupPath + "/" + backupFile)
|
||||
_ = os.Unsetenv("MYSQL_PWD")
|
||||
|
||||
return nil
|
||||
@@ -180,26 +183,26 @@ func (s *BackupImpl) MysqlRestore(database string, backupFile string) error {
|
||||
|
||||
switch ext {
|
||||
case ".zip":
|
||||
tools.ExecShell("unzip -o " + backupFile + " -d " + backupPath)
|
||||
tools.Exec("unzip -o " + backupFile + " -d " + backupPath)
|
||||
backupFile = strings.TrimSuffix(backupFile, ext)
|
||||
case ".gz":
|
||||
if strings.HasSuffix(backupFile, ".tar.gz") {
|
||||
// 解压.tar.gz文件
|
||||
tools.ExecShell("tar -zxvf " + backupFile + " -C " + backupPath)
|
||||
tools.Exec("tar -zxvf " + backupFile + " -C " + backupPath)
|
||||
backupFile = strings.TrimSuffix(backupFile, ".tar.gz")
|
||||
} else {
|
||||
// 解压.gz文件
|
||||
tools.ExecShell("gzip -d " + backupFile)
|
||||
tools.Exec("gzip -d " + backupFile)
|
||||
backupFile = strings.TrimSuffix(backupFile, ext)
|
||||
}
|
||||
case ".bz2":
|
||||
tools.ExecShell("bzip2 -d " + backupFile)
|
||||
tools.Exec("bzip2 -d " + backupFile)
|
||||
backupFile = strings.TrimSuffix(backupFile, ext)
|
||||
case ".tar":
|
||||
tools.ExecShell("tar -xvf " + backupFile + " -C " + backupPath)
|
||||
tools.Exec("tar -xvf " + backupFile + " -C " + backupPath)
|
||||
backupFile = strings.TrimSuffix(backupFile, ext)
|
||||
case ".rar":
|
||||
tools.ExecShell("unrar x " + backupFile + " " + backupPath)
|
||||
tools.Exec("unrar x " + backupFile + " " + backupPath)
|
||||
backupFile = strings.TrimSuffix(backupFile, ext)
|
||||
}
|
||||
|
||||
@@ -207,8 +210,97 @@ func (s *BackupImpl) MysqlRestore(database string, backupFile string) error {
|
||||
return errors.New("自动解压失败,请手动解压")
|
||||
}
|
||||
|
||||
tools.ExecShell("/www/server/mysql/bin/mysql -uroot " + database + " < " + backupFile)
|
||||
tools.Exec("/www/server/mysql/bin/mysql -uroot " + database + " < " + backupFile)
|
||||
_ = os.Unsetenv("MYSQL_PWD")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostgresqlList PostgreSQL备份列表
|
||||
func (s *BackupImpl) PostgresqlList() ([]BackupFile, error) {
|
||||
backupPath := s.setting.Get(models.SettingKeyBackupPath)
|
||||
if len(backupPath) == 0 {
|
||||
return []BackupFile{}, nil
|
||||
}
|
||||
|
||||
backupPath += "/postgresql"
|
||||
if !tools.Exists(backupPath) {
|
||||
tools.Mkdir(backupPath, 0644)
|
||||
}
|
||||
|
||||
files, err := os.ReadDir(backupPath)
|
||||
if err != nil {
|
||||
return []BackupFile{}, err
|
||||
}
|
||||
var backupList []BackupFile
|
||||
for _, file := range files {
|
||||
info, err := file.Info()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
backupList = append(backupList, BackupFile{
|
||||
Name: file.Name(),
|
||||
Size: tools.FormatBytes(float64(info.Size())),
|
||||
})
|
||||
}
|
||||
|
||||
return backupList, nil
|
||||
}
|
||||
|
||||
// PostgresqlBackup PostgreSQL备份
|
||||
func (s *BackupImpl) PostgresqlBackup(database string) error {
|
||||
backupPath := s.setting.Get(models.SettingKeyBackupPath) + "/postgresql"
|
||||
backupFile := database + "_" + carbon.Now().ToShortDateTimeString() + ".sql"
|
||||
if !tools.Exists(backupPath) {
|
||||
tools.Mkdir(backupPath, 0644)
|
||||
}
|
||||
|
||||
tools.Exec(`su - postgres -c "pg_dump ` + database + `" > ` + backupPath + "/" + backupFile)
|
||||
tools.Exec("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile)
|
||||
tools.Remove(backupPath + "/" + backupFile)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostgresqlRestore PostgreSQL恢复
|
||||
func (s *BackupImpl) PostgresqlRestore(database string, backupFile string) error {
|
||||
backupPath := s.setting.Get(models.SettingKeyBackupPath) + "/postgresql"
|
||||
ext := filepath.Ext(backupFile)
|
||||
backupFile = backupPath + "/" + backupFile
|
||||
if !tools.Exists(backupFile) {
|
||||
return errors.New("备份文件不存在")
|
||||
}
|
||||
|
||||
switch ext {
|
||||
case ".zip":
|
||||
tools.Exec("unzip -o " + backupFile + " -d " + backupPath)
|
||||
backupFile = strings.TrimSuffix(backupFile, ext)
|
||||
case ".gz":
|
||||
if strings.HasSuffix(backupFile, ".tar.gz") {
|
||||
// 解压.tar.gz文件
|
||||
tools.Exec("tar -zxvf " + backupFile + " -C " + backupPath)
|
||||
backupFile = strings.TrimSuffix(backupFile, ".tar.gz")
|
||||
} else {
|
||||
// 解压.gz文件
|
||||
tools.Exec("gzip -d " + backupFile)
|
||||
backupFile = strings.TrimSuffix(backupFile, ext)
|
||||
}
|
||||
case ".bz2":
|
||||
tools.Exec("bzip2 -d " + backupFile)
|
||||
backupFile = strings.TrimSuffix(backupFile, ext)
|
||||
case ".tar":
|
||||
tools.Exec("tar -xvf " + backupFile + " -C " + backupPath)
|
||||
backupFile = strings.TrimSuffix(backupFile, ext)
|
||||
case ".rar":
|
||||
tools.Exec("unrar x " + backupFile + " " + backupPath)
|
||||
backupFile = strings.TrimSuffix(backupFile, ext)
|
||||
}
|
||||
|
||||
if !tools.Exists(backupFile) {
|
||||
return errors.New("自动解压失败,请手动解压")
|
||||
}
|
||||
|
||||
tools.Exec(`su - postgres -c "psql ` + database + `" < ` + backupFile)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -22,11 +22,11 @@ func NewCronImpl() *CronImpl {
|
||||
// AddToSystem 添加到系统
|
||||
func (r *CronImpl) AddToSystem(cron models.Cron) {
|
||||
if tools.IsRHEL() {
|
||||
tools.ExecShell("echo \"" + cron.Time + " " + cron.Shell + " >> " + cron.Log + " 2>&1\" >> /var/spool/cron/root")
|
||||
tools.ExecShell("systemctl restart crond")
|
||||
tools.Exec("echo \"" + cron.Time + " " + cron.Shell + " >> " + cron.Log + " 2>&1\" >> /var/spool/cron/root")
|
||||
tools.Exec("systemctl restart crond")
|
||||
} else {
|
||||
tools.ExecShell("echo \"" + cron.Time + " " + cron.Shell + " >> " + cron.Log + " 2>&1\" >> /var/spool/cron/crontabs/root")
|
||||
tools.ExecShell("systemctl restart cron")
|
||||
tools.Exec("echo \"" + cron.Time + " " + cron.Shell + " >> " + cron.Log + " 2>&1\" >> /var/spool/cron/crontabs/root")
|
||||
tools.Exec("systemctl restart cron")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,10 +35,10 @@ func (r *CronImpl) DeleteFromSystem(cron models.Cron) {
|
||||
// 需要转义Shell路径的/为\/
|
||||
cron.Shell = strings.ReplaceAll(cron.Shell, "/", "\\/")
|
||||
if tools.IsRHEL() {
|
||||
tools.ExecShell("sed -i '/" + cron.Shell + "/d' /var/spool/cron/root")
|
||||
tools.ExecShell("systemctl restart crond")
|
||||
tools.Exec("sed -i '/" + cron.Shell + "/d' /var/spool/cron/root")
|
||||
tools.Exec("systemctl restart crond")
|
||||
} else {
|
||||
tools.ExecShell("sed -i '/" + cron.Shell + "/d' /var/spool/cron/crontabs/root")
|
||||
tools.ExecShell("systemctl restart cron")
|
||||
tools.Exec("sed -i '/" + cron.Shell + "/d' /var/spool/cron/crontabs/root")
|
||||
tools.Exec("systemctl restart cron")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,12 @@ import (
|
||||
"panel/app/plugins/php81"
|
||||
"panel/app/plugins/php82"
|
||||
"panel/app/plugins/phpmyadmin"
|
||||
"panel/app/plugins/postgresql15"
|
||||
"panel/app/plugins/pureftpd"
|
||||
"panel/app/plugins/redis"
|
||||
"panel/app/plugins/s3fs"
|
||||
"panel/app/plugins/supervisor"
|
||||
"panel/app/plugins/toolbox"
|
||||
)
|
||||
|
||||
// PanelPlugin 插件元数据结构
|
||||
@@ -93,6 +96,17 @@ func (r *PluginImpl) All() []PanelPlugin {
|
||||
Uninstall: mysql80.Uninstall,
|
||||
Update: mysql80.Update,
|
||||
})
|
||||
p = append(p, PanelPlugin{
|
||||
Name: postgresql15.Name,
|
||||
Description: postgresql15.Description,
|
||||
Slug: postgresql15.Slug,
|
||||
Version: postgresql15.Version,
|
||||
Requires: postgresql15.Requires,
|
||||
Excludes: postgresql15.Excludes,
|
||||
Install: postgresql15.Install,
|
||||
Uninstall: postgresql15.Uninstall,
|
||||
Update: postgresql15.Update,
|
||||
})
|
||||
p = append(p, PanelPlugin{
|
||||
Name: php74.Name,
|
||||
Description: php74.Description,
|
||||
@@ -159,6 +173,17 @@ func (r *PluginImpl) All() []PanelPlugin {
|
||||
Uninstall: pureftpd.Uninstall,
|
||||
Update: pureftpd.Update,
|
||||
})
|
||||
p = append(p, PanelPlugin{
|
||||
Name: redis.Name,
|
||||
Description: redis.Description,
|
||||
Slug: redis.Slug,
|
||||
Version: redis.Version,
|
||||
Requires: redis.Requires,
|
||||
Excludes: redis.Excludes,
|
||||
Install: redis.Install,
|
||||
Uninstall: redis.Uninstall,
|
||||
Update: redis.Update,
|
||||
})
|
||||
p = append(p, PanelPlugin{
|
||||
Name: s3fs.Name,
|
||||
Description: s3fs.Description,
|
||||
@@ -192,6 +217,17 @@ func (r *PluginImpl) All() []PanelPlugin {
|
||||
Uninstall: fail2ban.Uninstall,
|
||||
Update: fail2ban.Update,
|
||||
})
|
||||
p = append(p, PanelPlugin{
|
||||
Name: toolbox.Name,
|
||||
Description: toolbox.Description,
|
||||
Slug: toolbox.Slug,
|
||||
Version: toolbox.Version,
|
||||
Requires: toolbox.Requires,
|
||||
Excludes: toolbox.Excludes,
|
||||
Install: toolbox.Install,
|
||||
Uninstall: toolbox.Uninstall,
|
||||
Update: toolbox.Update,
|
||||
})
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
+22
-22
@@ -129,7 +129,7 @@ func (r *WebsiteImpl) Add(website PanelWebsite) (models.Website, error) {
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
tools.WriteFile(website.Path+"/index.html", index, 0644)
|
||||
tools.Write(website.Path+"/index.html", index, 0644)
|
||||
|
||||
domainArr := strings.Split(website.Domain, "\n")
|
||||
portList := ""
|
||||
@@ -217,24 +217,24 @@ server
|
||||
}
|
||||
`, portList, domainList, website.Path, website.Php, website.Name, website.Name, website.Name)
|
||||
|
||||
tools.WriteFile("/www/server/vhost/"+website.Name+".conf", nginxConf, 0644)
|
||||
tools.WriteFile("/www/server/vhost/rewrite/"+website.Name+".conf", "", 0644)
|
||||
tools.WriteFile("/www/server/vhost/ssl/"+website.Name+".pem", "", 0644)
|
||||
tools.WriteFile("/www/server/vhost/ssl/"+website.Name+".key", "", 0644)
|
||||
tools.Write("/www/server/vhost/"+website.Name+".conf", nginxConf, 0644)
|
||||
tools.Write("/www/server/vhost/rewrite/"+website.Name+".conf", "", 0644)
|
||||
tools.Write("/www/server/vhost/ssl/"+website.Name+".pem", "", 0644)
|
||||
tools.Write("/www/server/vhost/ssl/"+website.Name+".key", "", 0644)
|
||||
|
||||
tools.Chmod(r.setting.Get(models.SettingKeyWebsitePath), 0755)
|
||||
tools.Chmod(website.Path, 0755)
|
||||
tools.Chown(r.setting.Get(models.SettingKeyWebsitePath), "www", "www")
|
||||
tools.Chown(website.Path, "www", "www")
|
||||
|
||||
tools.ExecShell("systemctl reload openresty")
|
||||
tools.Exec("systemctl reload openresty")
|
||||
|
||||
rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
if website.Db && website.DbType == "mysql" {
|
||||
tools.ExecShell(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE DATABASE IF NOT EXISTS ` + website.DbName + ` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;"`)
|
||||
tools.ExecShell(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE USER '` + website.DbUser + `'@'localhost' IDENTIFIED BY '` + website.DbPassword + `';"`)
|
||||
tools.ExecShell(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "GRANT ALL PRIVILEGES ON ` + website.DbName + `.* TO '` + website.DbUser + `'@'localhost';"`)
|
||||
tools.ExecShell(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "FLUSH PRIVILEGES;"`)
|
||||
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;"`)
|
||||
}
|
||||
|
||||
return w, nil
|
||||
@@ -251,13 +251,13 @@ func (r *WebsiteImpl) Delete(id int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
tools.RemoveFile("/www/server/vhost/" + website.Name + ".conf")
|
||||
tools.RemoveFile("/www/server/vhost/rewrite/" + website.Name + ".conf")
|
||||
tools.RemoveFile("/www/server/vhost/ssl/" + website.Name + ".pem")
|
||||
tools.RemoveFile("/www/server/vhost/ssl/" + website.Name + ".key")
|
||||
tools.RemoveFile(website.Path)
|
||||
tools.Remove("/www/server/vhost/" + website.Name + ".conf")
|
||||
tools.Remove("/www/server/vhost/rewrite/" + website.Name + ".conf")
|
||||
tools.Remove("/www/server/vhost/ssl/" + website.Name + ".pem")
|
||||
tools.Remove("/www/server/vhost/ssl/" + website.Name + ".key")
|
||||
tools.Remove(website.Path)
|
||||
|
||||
tools.ExecShell("systemctl reload openresty")
|
||||
tools.Exec("systemctl reload openresty")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -269,7 +269,7 @@ func (r *WebsiteImpl) GetConfig(id int) (WebsiteSetting, error) {
|
||||
return WebsiteSetting{}, err
|
||||
}
|
||||
|
||||
config := tools.ReadFile("/www/server/vhost/" + website.Name + ".conf")
|
||||
config := tools.Read("/www/server/vhost/" + website.Name + ".conf")
|
||||
|
||||
var setting WebsiteSetting
|
||||
setting.Name = website.Name
|
||||
@@ -303,7 +303,7 @@ func (r *WebsiteImpl) GetConfig(id int) (WebsiteSetting, error) {
|
||||
}
|
||||
|
||||
if tools.Exists(setting.Root + "/.user.ini") {
|
||||
userIni := tools.ReadFile(setting.Path + "/.user.ini")
|
||||
userIni := tools.Read(setting.Path + "/.user.ini")
|
||||
if strings.Contains(userIni, "open_basedir") {
|
||||
setting.OpenBasedir = true
|
||||
} else {
|
||||
@@ -313,8 +313,8 @@ func (r *WebsiteImpl) GetConfig(id int) (WebsiteSetting, error) {
|
||||
setting.OpenBasedir = false
|
||||
}
|
||||
|
||||
setting.SslCertificate = tools.ReadFile("/www/server/vhost/ssl/" + website.Name + ".pem")
|
||||
setting.SslCertificateKey = tools.ReadFile("/www/server/vhost/ssl/" + website.Name + ".key")
|
||||
setting.SslCertificate = tools.Read("/www/server/vhost/ssl/" + website.Name + ".pem")
|
||||
setting.SslCertificateKey = tools.Read("/www/server/vhost/ssl/" + website.Name + ".key")
|
||||
if setting.Ssl {
|
||||
ssl := tools.Cut(config, "# ssl标记位开始", "# ssl标记位结束")
|
||||
setting.HttpRedirect = strings.Contains(ssl, "# http重定向标记位")
|
||||
@@ -339,8 +339,8 @@ func (r *WebsiteImpl) GetConfig(id int) (WebsiteSetting, error) {
|
||||
setting.WafCache = match[1]
|
||||
}
|
||||
|
||||
setting.Rewrite = tools.ReadFile("/www/server/vhost/rewrite/" + website.Name + ".conf")
|
||||
setting.Log = tools.ExecShell(`tail -n 100 '/www/wwwlogs/` + website.Name + `.log'`)
|
||||
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'`))
|
||||
|
||||
return setting, nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package bootstrap
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/foundation"
|
||||
"github.com/goravel/framework/support/carbon"
|
||||
|
||||
"panel/config"
|
||||
)
|
||||
@@ -15,7 +14,4 @@ func Boot() {
|
||||
|
||||
// Bootstrap the config.
|
||||
config.Boot()
|
||||
|
||||
// 设置 Carbon 时区
|
||||
carbon.SetTimezone(carbon.PRC)
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,6 +8,6 @@ func init() {
|
||||
config := facades.Config()
|
||||
config.Add("panel", map[string]any{
|
||||
"name": "耗子Linux面板",
|
||||
"version": "v2.0.26",
|
||||
"version": "v2.0.33",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,16 +7,16 @@ require (
|
||||
github.com/gertd/go-pluralize v0.2.1
|
||||
github.com/gin-contrib/static v0.0.1
|
||||
github.com/gookit/color v1.5.4
|
||||
github.com/goravel/framework v1.12.1-0.20230726100652-342097efc4ce
|
||||
github.com/goravel/framework v1.12.1-0.20230809103226-03eb8ad21087
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/iancoleman/strcase v0.2.0
|
||||
github.com/imroc/req/v3 v3.37.2
|
||||
github.com/iancoleman/strcase v0.3.0
|
||||
github.com/imroc/req/v3 v3.40.1
|
||||
github.com/mojocn/base64Captcha v1.3.5
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/spf13/cast v1.5.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
golang.org/x/crypto v0.11.0
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
|
||||
golang.org/x/crypto v0.12.0
|
||||
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -51,7 +51,7 @@ require (
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gaukas/godicttls v0.0.3 // indirect
|
||||
github.com/gaukas/godicttls v0.0.4 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/gin-gonic/gin v1.9.1 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
@@ -80,7 +80,7 @@ require (
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect
|
||||
github.com/google/pprof v0.0.0-20230808223545-4887780b67fb // indirect
|
||||
github.com/google/s2a-go v0.1.3 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
@@ -89,7 +89,7 @@ require (
|
||||
github.com/googleapis/gax-go/v2 v2.8.0 // indirect
|
||||
github.com/gookit/filter v1.2.0 // indirect
|
||||
github.com/gookit/goutil v0.6.12 // indirect
|
||||
github.com/gookit/validate v1.5.0 // indirect
|
||||
github.com/gookit/validate v1.5.1 // indirect
|
||||
github.com/goravel/file-rotatelogs v0.0.0-20211215053220-2ab31dd9575c // indirect
|
||||
github.com/goravel/file-rotatelogs/v2 v2.4.1 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
@@ -106,7 +106,7 @@ require (
|
||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kelseyhightower/envconfig v1.4.0 // indirect
|
||||
github.com/klauspost/compress v1.16.6 // indirect
|
||||
github.com/klauspost/compress v1.16.7 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/lestrrat-go/strftime v1.0.5 // indirect
|
||||
@@ -129,10 +129,9 @@ require (
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
|
||||
github.com/quic-go/quic-go v0.36.0 // indirect
|
||||
github.com/refraction-networking/utls v1.3.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.2 // indirect
|
||||
github.com/quic-go/quic-go v0.37.4 // indirect
|
||||
github.com/refraction-networking/utls v1.3.3 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
@@ -163,21 +162,21 @@ require (
|
||||
go.mongodb.org/mongo-driver v1.7.5 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/net v0.11.0 // indirect
|
||||
golang.org/x/arch v0.4.0 // indirect
|
||||
golang.org/x/image v0.11.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.14.0 // indirect
|
||||
golang.org/x/oauth2 v0.7.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/tools v0.12.0 // indirect
|
||||
google.golang.org/api v0.122.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230525234025-438c736192d0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a // indirect
|
||||
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||
google.golang.org/grpc v1.56.2 // indirect
|
||||
google.golang.org/grpc v1.57.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
@@ -186,7 +185,7 @@ require (
|
||||
gorm.io/driver/postgres v1.5.2 // indirect
|
||||
gorm.io/driver/sqlserver v1.5.1 // indirect
|
||||
gorm.io/gorm v1.25.2 // indirect
|
||||
gorm.io/plugin/dbresolver v1.4.1 // indirect
|
||||
gorm.io/plugin/dbresolver v1.4.2 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
|
||||
@@ -85,7 +85,7 @@ github.com/aws/aws-sdk-go v1.37.16 h1:Q4YOP2s00NpB9wfmTDZArdcLRuG9ijbnoAwTW3ivle
|
||||
github.com/aws/aws-sdk-go v1.37.16/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/brianvoe/gofakeit/v6 v6.23.0 h1:pgVhyWpYq4e0GEVCh2gdZnS/nBX+8SnyTBliHg5xjks=
|
||||
github.com/brianvoe/gofakeit/v6 v6.23.1 h1:k2gX0hQpJStvixDbbw8oJOvPBg0XmHJWbSOF5JkiUHw=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM=
|
||||
github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
@@ -156,8 +156,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gaukas/godicttls v0.0.3 h1:YNDIf0d9adcxOijiLrEzpfZGAkNwLRzPaG6OjU7EITk=
|
||||
github.com/gaukas/godicttls v0.0.3/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
||||
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
|
||||
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
||||
github.com/gertd/go-pluralize v0.2.1 h1:M3uASbVjMnTsPb0PNqg+E/24Vwigyo/tvyMTtAlLgiA=
|
||||
github.com/gertd/go-pluralize v0.2.1/go.mod h1:rbYaKDbsXxmRfr8uygAEKhOWsjyrrqrkHVpZvoOp8zk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -324,8 +324,8 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs=
|
||||
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=
|
||||
github.com/google/pprof v0.0.0-20230808223545-4887780b67fb h1:oqpb3Cwpc7EOml5PVGMYbSGmwNui2R7i8IW83gs4W0c=
|
||||
github.com/google/pprof v0.0.0-20230808223545-4887780b67fb/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE=
|
||||
github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
|
||||
@@ -351,14 +351,14 @@ github.com/gookit/filter v1.2.0 h1:r7E01dHVkysb5WgzooiGsfblHGShEZCeGcyYM+5IpYU=
|
||||
github.com/gookit/filter v1.2.0/go.mod h1:bXs9RcB4Blxwny970opiwABeIEqQ/gzOMmHBhKwBdms=
|
||||
github.com/gookit/goutil v0.6.12 h1:73vPUcTtVGXbhSzBOFcnSB1aJl7Jq9np3RAE50yIDZc=
|
||||
github.com/gookit/goutil v0.6.12/go.mod h1:g6krlFib8xSe3G1h02IETowOtrUGpAmetT8IevDpvpM=
|
||||
github.com/gookit/validate v1.5.0 h1:aTy974I1vPDYPFzoFH4vtJONrK4oRDvjUxteUan7beE=
|
||||
github.com/gookit/validate v1.5.0/go.mod h1:SskOHUQokzMNt6T3r7N+N/4me/6fxDx+tmoXf/3ZQog=
|
||||
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/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.12.1-0.20230726100652-342097efc4ce h1:1qgkBySstIMAkzRjbrjPjF6J0UIKBfXY1osSfL7azNY=
|
||||
github.com/goravel/framework v1.12.1-0.20230726100652-342097efc4ce/go.mod h1:qLv6cmf4RqXkTZ782H38cY/7vhkFLamPV9pAU0s7nKQ=
|
||||
github.com/goravel/framework v1.12.1-0.20230809103226-03eb8ad21087 h1:YOKs5GFzbWOZz3ojiX5jl082Y1BRGOCig3ldnNBTrRs=
|
||||
github.com/goravel/framework v1.12.1-0.20230809103226-03eb8ad21087/go.mod h1:qc8dK2vVVVdTSashuby7+KZZ2CfGztNgMaoDGWtvtVI=
|
||||
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/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
@@ -379,14 +379,14 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
|
||||
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
||||
github.com/imroc/req/v3 v3.37.2 h1:vEemuA0cq9zJ6lhe+mSRhsZm951bT0CdiSH47+KTn6I=
|
||||
github.com/imroc/req/v3 v3.37.2/go.mod h1:DECzjVIrj6jcUr5n6e+z0ygmCO93rx4Jy0RjOEe1YCI=
|
||||
github.com/imroc/req/v3 v3.40.1 h1:/7YAmkrI4HsOTO6Md5FUUWPId90bTD074BV8sA0bt18=
|
||||
github.com/imroc/req/v3 v3.40.1/go.mod h1:4wMbz0QYY5jmXNWk0BsWrRTR9ItZqOxzSJdGL0M9kzY=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
@@ -428,8 +428,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk=
|
||||
github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
@@ -525,14 +525,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||
github.com/quic-go/quic-go v0.36.0 h1:JIrO7p7Ug6hssFcARjWDiqS2RAKJHCiwPxBAA989rbI=
|
||||
github.com/quic-go/quic-go v0.36.0/go.mod h1:zPetvwDlILVxt15n3hr3Gf/I3mDf7LpLKPhR4Ez0AZQ=
|
||||
github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8=
|
||||
github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.37.4 h1:ke8B73yMCWGq9MfrCCAw0Uzdm7GaViC3i39dsIdDlH4=
|
||||
github.com/quic-go/quic-go v0.37.4/go.mod h1:YsbH1r4mSHPJcLF4k4zruUkLBqctEMBDR6VPvcYjIsU=
|
||||
github.com/refraction-networking/utls v1.3.3 h1:f/TBLX7KBciRyFH3bwupp+CE4fzoYKCirhdRcC490sw=
|
||||
github.com/refraction-networking/utls v1.3.3/go.mod h1:DlecWW1LMlMJu+9qpzzQqdHDT/C2LAe03EdpLUz/RL8=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
@@ -671,8 +669,8 @@ go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc=
|
||||
golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
@@ -690,8 +688,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
|
||||
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.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
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=
|
||||
@@ -702,12 +700,13 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 h1:EDuYyU/MkFXllv9QF9819VlI9a4tzGuCbhG0ExK9o1U=
|
||||
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
|
||||
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -732,8 +731,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -777,8 +776,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -876,14 +875,14 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
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.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
||||
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
|
||||
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=
|
||||
@@ -897,8 +896,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -962,8 +961,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
|
||||
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1037,10 +1036,10 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20230525234025-438c736192d0 h1:x1vNwUhVOcsYoKyEGCZBH694SBmmBjA2EfauFVEI2+M=
|
||||
google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a h1:HiYVD+FGJkTo+9zj1gqz0anapsa1JxjiSrN+BJKyUmE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8=
|
||||
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M=
|
||||
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -1062,8 +1061,8 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
|
||||
google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
|
||||
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -1112,12 +1111,11 @@ gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBp
|
||||
gorm.io/driver/sqlserver v1.5.1 h1:wpyW/pR26U94uaujltiFGXY7fd2Jw5hC9PB1ZF/Y5s4=
|
||||
gorm.io/driver/sqlserver v1.5.1/go.mod h1:AYHzzte2msKTmYBYsSIq8ZUsznLJwBdkB2wpI+kt0nM=
|
||||
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.24.3/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||
gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
|
||||
gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||
gorm.io/plugin/dbresolver v1.4.1 h1:Ug4LcoPhrvqq71UhxtF346f+skTYoCa/nEsdjvHwEzk=
|
||||
gorm.io/plugin/dbresolver v1.4.1/go.mod h1:CTbCtMWhsjXSiJqiW2R8POvJ2cq18RVOl4WGyT5nhNc=
|
||||
gorm.io/plugin/dbresolver v1.4.2 h1:IeLSH20ayxbo4rN6HMIQ0ccdsh/fkLK23pp6ivZrqBI=
|
||||
gorm.io/plugin/dbresolver v1.4.2/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0=
|
||||
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
+1
-1
@@ -68,5 +68,5 @@ func NewSSHClient(conf *SSHClientConfig) (*ssh.Client, error) {
|
||||
}
|
||||
|
||||
func getKey(keyPath string) (ssh.Signer, error) {
|
||||
return ssh.ParsePrivateKey([]byte(tools.ReadFile(keyPath)))
|
||||
return ssh.ParsePrivateKey([]byte(tools.Read(keyPath)))
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
@@ -78,3 +79,8 @@ func Cut(str, begin, end string) string {
|
||||
|
||||
return string([]rune(str)[b:e])
|
||||
}
|
||||
|
||||
// Escape 转义字符串
|
||||
func Escape(str string) string {
|
||||
return template.HTMLEscapeString(str)
|
||||
}
|
||||
|
||||
+45
-17
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/goravel/framework/facades"
|
||||
)
|
||||
|
||||
// WriteFile 写入文件
|
||||
func WriteFile(path string, data string, permission os.FileMode) bool {
|
||||
// Write 写入文件
|
||||
func Write(path string, data string, permission os.FileMode) bool {
|
||||
if err := os.MkdirAll(filepath.Dir(path), permission); err != nil {
|
||||
facades.Log().Errorf("[面板][Helpers] 创建目录失败: %s", err.Error())
|
||||
return false
|
||||
@@ -25,8 +25,8 @@ func WriteFile(path string, data string, permission os.FileMode) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadFile 读取文件
|
||||
func ReadFile(path string) string {
|
||||
// Read 读取文件
|
||||
func Read(path string) string {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
facades.Log().Errorf("[面板][Helpers] 读取文件 %s 失败: %s", path, err.Error())
|
||||
@@ -36,8 +36,8 @@ func ReadFile(path string) string {
|
||||
return string(data)
|
||||
}
|
||||
|
||||
// RemoveFile 删除文件
|
||||
func RemoveFile(path string) bool {
|
||||
// Remove 删除文件
|
||||
func Remove(path string) bool {
|
||||
if err := os.Remove(path); err != nil {
|
||||
facades.Log().Errorf("[面板][Helpers] 删除文件 %s 失败: %s", path, err.Error())
|
||||
return false
|
||||
@@ -46,8 +46,8 @@ func RemoveFile(path string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// ExecShell 执行 shell 命令
|
||||
func ExecShell(shell string) string {
|
||||
// Exec 执行 shell 命令
|
||||
func Exec(shell string) string {
|
||||
cmd := exec.Command("bash", "-c", shell)
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
@@ -59,8 +59,8 @@ func ExecShell(shell string) string {
|
||||
return strings.TrimSpace(string(output))
|
||||
}
|
||||
|
||||
// ExecShellAsync 异步执行 shell 命令
|
||||
func ExecShellAsync(shell string) {
|
||||
// ExecAsync 异步执行 shell 命令
|
||||
func ExecAsync(shell string) {
|
||||
cmd := exec.Command("bash", "-c", shell)
|
||||
|
||||
err := cmd.Start()
|
||||
@@ -126,27 +126,55 @@ func Empty(path string) bool {
|
||||
}
|
||||
|
||||
// Mv 移动路径
|
||||
func Mv(src, dst string) bool {
|
||||
func Mv(src, dst string) (bool, error) {
|
||||
cmd := exec.Command("mv", src, dst)
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
facades.Log().Errorf("[面板][Helpers] 移动 %s 到 %s 失败: %s", src, dst, err.Error())
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Cp 复制路径
|
||||
func Cp(src, dst string) bool {
|
||||
func Cp(src, dst string) (bool, error) {
|
||||
cmd := exec.Command("cp", "-r", src, dst)
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
facades.Log().Errorf("[面板][Helpers] 复制 %s 到 %s 失败: %s", src, dst, err.Error())
|
||||
return false
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Size 获取路径大小
|
||||
func Size(path string) (int64, error) {
|
||||
var size int64
|
||||
|
||||
err := filepath.Walk(path, func(filePath string, info os.FileInfo, walkErr error) error {
|
||||
if walkErr != nil {
|
||||
return walkErr
|
||||
}
|
||||
size += info.Size()
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// FileSize 获取文件大小
|
||||
func FileSize(path string) (int64, error) {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return info.Size(), nil
|
||||
}
|
||||
|
||||
+44
-10
@@ -17,45 +17,45 @@ func TestSystemHelperTestSuite(t *testing.T) {
|
||||
suite.Run(t, &SystemHelperTestSuite{})
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestWriteFile() {
|
||||
func (s *SystemHelperTestSuite) TestWrite() {
|
||||
filePath := "/tmp/testfile"
|
||||
defer os.Remove(filePath)
|
||||
|
||||
s.True(WriteFile(filePath, "test data", 0644))
|
||||
s.True(Write(filePath, "test data", 0644))
|
||||
s.FileExists(filePath)
|
||||
|
||||
content, _ := os.ReadFile(filePath)
|
||||
s.Equal("test data", string(content))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestReadFile() {
|
||||
func (s *SystemHelperTestSuite) TestRead() {
|
||||
filePath := "/tmp/testfile"
|
||||
defer os.Remove(filePath)
|
||||
|
||||
err := os.WriteFile(filePath, []byte("test data"), 0644)
|
||||
s.Nil(err)
|
||||
|
||||
s.Equal("test data", ReadFile(filePath))
|
||||
s.Equal("test data", Read(filePath))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestRemoveFile() {
|
||||
func (s *SystemHelperTestSuite) TestRemove() {
|
||||
filePath := "/tmp/testfile"
|
||||
|
||||
err := os.WriteFile(filePath, []byte("test data"), 0644)
|
||||
s.Nil(err)
|
||||
|
||||
s.True(RemoveFile(filePath))
|
||||
s.True(Remove(filePath))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestExecShell() {
|
||||
s.Equal("test", ExecShell("echo 'test'"))
|
||||
func (s *SystemHelperTestSuite) TestExec() {
|
||||
s.Equal("test", Exec("echo 'test'"))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestExecShellAsync() {
|
||||
func (s *SystemHelperTestSuite) TestExecAsync() {
|
||||
command := "echo 'test' > /tmp/testfile"
|
||||
defer os.Remove("/tmp/testfile")
|
||||
|
||||
ExecShellAsync(command)
|
||||
ExecAsync(command)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
@@ -104,3 +104,37 @@ func (s *SystemHelperTestSuite) TestEmpty() {
|
||||
s.True(Empty("/tmp/123"))
|
||||
s.False(Empty("/tmp"))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestMv() {
|
||||
filePath := "/tmp/testfile"
|
||||
defer os.Remove(filePath)
|
||||
|
||||
err := os.WriteFile(filePath, []byte("test data"), 0644)
|
||||
s.Nil(err)
|
||||
|
||||
s.True(Mv(filePath, "/tmp/testfile2"))
|
||||
s.False(Exists(filePath))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestCp() {
|
||||
filePath := "/tmp/testfile"
|
||||
defer os.Remove(filePath)
|
||||
|
||||
err := os.WriteFile(filePath, []byte("test data"), 0644)
|
||||
s.Nil(err)
|
||||
|
||||
s.True(Cp(filePath, "/tmp/testfile2"))
|
||||
s.True(Exists(filePath))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestSize() {
|
||||
size, err := Size("/tmp/123")
|
||||
s.Equal(int64(0), size)
|
||||
s.Error(err)
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestFileSize() {
|
||||
size, err := FileSize("/tmp/123")
|
||||
s.Equal(int64(0), size)
|
||||
s.Error(err)
|
||||
}
|
||||
|
||||
+12
-10
@@ -127,40 +127,42 @@ func UpdatePanel(proxy bool) error {
|
||||
color.Greenln("使用代理: " + strconv.FormatBool(proxy))
|
||||
|
||||
color.Greenln("备份面板配置...")
|
||||
ExecShell("cp -f /www/panel/database/panel.db /tmp/panel.db.bak")
|
||||
ExecShell("cp -f /www/panel/panel.conf /tmp/panel.conf.bak")
|
||||
Exec("cp -f /www/panel/database/panel.db /tmp/panel.db.bak")
|
||||
Exec("cp -f /www/panel/panel.conf /tmp/panel.conf.bak")
|
||||
if !Exists("/tmp/panel.db.bak") || !Exists("/tmp/panel.conf.bak") {
|
||||
return errors.New("备份面板配置失败")
|
||||
}
|
||||
color.Greenln("备份完成")
|
||||
|
||||
color.Greenln("清理旧版本...")
|
||||
ExecShell("rm -rf /www/panel/*")
|
||||
Exec("rm -rf /www/panel/*")
|
||||
color.Greenln("清理完成")
|
||||
|
||||
color.Greenln("正在下载...")
|
||||
if proxy {
|
||||
ExecShell("wget -O /www/panel/panel.zip https://ghproxy.com/" + panelInfo.DownloadUrl)
|
||||
Exec("wget -O /www/panel/panel.zip https://ghproxy.com/" + panelInfo.DownloadUrl)
|
||||
} else {
|
||||
ExecShell("wget -O /www/panel/panel.zip " + panelInfo.DownloadUrl)
|
||||
Exec("wget -O /www/panel/panel.zip " + panelInfo.DownloadUrl)
|
||||
}
|
||||
color.Greenln("下载完成")
|
||||
|
||||
color.Greenln("更新新版本...")
|
||||
ExecShell("cd /www/panel && unzip -o panel.zip && rm -rf panel.zip && chmod 700 panel")
|
||||
Exec("cd /www/panel && unzip -o panel.zip && rm -rf panel.zip && chmod 700 panel && bash scripts/update_panel.sh")
|
||||
color.Greenln("更新完成")
|
||||
|
||||
color.Greenln("恢复面板配置...")
|
||||
ExecShell("cp -f /tmp/panel.db.bak /www/panel/database/panel.db")
|
||||
ExecShell("cp -f /tmp/panel.conf.bak /www/panel/panel.conf")
|
||||
Exec("cp -f /tmp/panel.db.bak /www/panel/database/panel.db")
|
||||
Exec("cp -f /tmp/panel.conf.bak /www/panel/panel.conf")
|
||||
if !Exists("/www/panel/database/panel.db") || !Exists("/www/panel/panel.conf") {
|
||||
return errors.New("恢复面板配置失败")
|
||||
}
|
||||
ExecShell("/www/panel/panel --env=panel.conf artisan migrate")
|
||||
Exec("/www/panel/panel --env=panel.conf artisan migrate")
|
||||
color.Greenln("恢复完成")
|
||||
|
||||
Exec("panel writeSetting version " + panelInfo.Version)
|
||||
|
||||
color.Greenln("重启面板...")
|
||||
ExecShell("systemctl restart panel")
|
||||
Exec("systemctl restart panel")
|
||||
color.Greenln("重启完成")
|
||||
|
||||
return nil
|
||||
|
||||
@@ -37,7 +37,7 @@ layui.define(['laytpl', 'layer'], function (exports) {
|
||||
})
|
||||
|
||||
//跳转到登入页
|
||||
location.hash = '/user/login'
|
||||
location.hash = '/login'
|
||||
}
|
||||
|
||||
//Ajax请求
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<!--
|
||||
Name: 资源监控
|
||||
Author: 耗子
|
||||
Date: 2023-07-21
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<title>资源监控</title>
|
||||
|
||||
@@ -93,18 +92,16 @@ Date: 2023-07-21
|
||||
<script>
|
||||
layui.use(['admin', 'view', 'form', 'element', 'carousel'], function () {
|
||||
var admin = layui.admin;
|
||||
var view = layui.view;
|
||||
var $ = layui.jquery;
|
||||
var form = layui.form;
|
||||
var laydate = layui.laydate;
|
||||
|
||||
// 渲染时间选择器
|
||||
// 默认开始时间为今天0点,结束时间为当前时间
|
||||
var startDate = new Date(new Date().setHours(0, 0, 0, 0));
|
||||
var endDate = new Date();
|
||||
// 拼接时间字符串
|
||||
var startStr = startDate.getFullYear() + '-' + (startDate.getMonth() + 1) + '-' + startDate.getDate() + ' ' + startDate.getHours() + ':' + startDate.getMinutes() + ':' + startDate.getSeconds();
|
||||
var endStr = endDate.getFullYear() + '-' + (endDate.getMonth() + 1) + '-' + endDate.getDate() + ' ' + endDate.getHours() + ':' + endDate.getMinutes() + ':' + endDate.getSeconds();
|
||||
var startStr = startDate.getFullYear() + '-' + startDate.getMonth() + '-' + startDate.getDate() + ' ' + startDate.getHours() + ':' + startDate.getMinutes() + ':' + startDate.getSeconds();
|
||||
var endStr = endDate.getFullYear() + '-' + endDate.getMonth() + '-' + endDate.getDate() + ' ' + endDate.getHours() + ':' + endDate.getMinutes() + ':' + endDate.getSeconds();
|
||||
laydate.render({
|
||||
elem: '#monitor-date'
|
||||
, type: 'datetime'
|
||||
@@ -139,7 +136,6 @@ Date: 2023-07-21
|
||||
}
|
||||
}
|
||||
});
|
||||
// 监听switch开关:是否开启监控
|
||||
form.on('switch(monitor)', function (data) {
|
||||
admin.req({
|
||||
url: '/api/panel/monitor/switch',
|
||||
@@ -155,7 +151,6 @@ Date: 2023-07-21
|
||||
}
|
||||
});
|
||||
});
|
||||
// 监听保存天数按钮
|
||||
$('#save_monitor_date').click(function () {
|
||||
var days = $('input[name="monitor-save-days"]').val();
|
||||
if (days == '') {
|
||||
@@ -176,8 +171,6 @@ Date: 2023-07-21
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 监听清除监控数据按钮
|
||||
$('#clear_monitor_record').click(function () {
|
||||
layer.confirm('确定要清除监控数据吗?', function (index) {
|
||||
admin.req({
|
||||
@@ -202,12 +195,10 @@ Date: 2023-07-21
|
||||
getMonitorData(startDate.getTime(), endDate.getTime());
|
||||
});
|
||||
|
||||
|
||||
// 获取监控数据
|
||||
function getMonitorData(startDate, endDate) {
|
||||
layui.use(['admin'], function () {
|
||||
let admin = layui.admin;
|
||||
// 获取监控数据
|
||||
admin.req({
|
||||
url: '/api/panel/monitor/list?start=' + startDate + '&end=' + endDate,
|
||||
type: 'get',
|
||||
|
||||
@@ -0,0 +1,524 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<title>PostgreSQL</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">PostgreSQL管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">基本信息</li>
|
||||
<li>管理</li>
|
||||
<li>主配置</li>
|
||||
<li>用户配置</li>
|
||||
<li>负载状态</li>
|
||||
<li>日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>运行状态</legend>
|
||||
</fieldset>
|
||||
<blockquote id="postgresql-status" class="layui-elem-quote layui-quote-nm">
|
||||
当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="postgresql-start" class="layui-btn">启动</button>
|
||||
<button id="postgresql-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="postgresql-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="postgresql-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">面板仅集成了部分常用功能,如需更多功能,请使用
|
||||
pgAdmin 客户端。
|
||||
</blockquote>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>数据库列表</legend>
|
||||
</fieldset>
|
||||
<table class="layui-hide" id="postgresql-database-list"
|
||||
lay-filter="postgresql-database-list"></table>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
|
||||
<legend>用户列表</legend>
|
||||
</fieldset>
|
||||
<table class="layui-hide" id="postgresql-user-list"
|
||||
lay-filter="postgresql-user-list"></table>
|
||||
<!-- 数据库顶部工具栏 -->
|
||||
<script type="text/html" id="postgresql-database-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_database">新建数据库
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 用户顶部工具栏 -->
|
||||
<script type="text/html" id="postgresql-user-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_user">新建用户</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 数据库右侧管理 -->
|
||||
<script type="text/html" id="postgresql-database-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="backup">备份</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<!-- 用户右侧管理 -->
|
||||
<script type="text/html" id="postgresql-user-list-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs"
|
||||
lay-event="change_password">改密</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是PostgreSQL主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="postgresql-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="postgresql-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是PostgreSQL用户配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="postgresql-user-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="postgresql-user-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="postgresql-load-status"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<pre id="postgresql-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let postgresql_config_editor;
|
||||
let postgresql_user_config_editor;
|
||||
layui.use(['index', 'admin', 'element', 'form', 'view', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, code = layui.code
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view;
|
||||
|
||||
form.render();
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#postgresql-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#postgresql-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据库列表
|
||||
table.render({
|
||||
elem: '#postgresql-database-list'
|
||||
, url: '/api/plugins/postgresql15/database'
|
||||
, toolbar: '#postgresql-database-list-bar'
|
||||
, title: '数据库列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '库名', fixed: 'left', unresize: true, sort: true}
|
||||
, {field: 'owner', title: '所有者', unresize: true, sort: true}
|
||||
, {field: 'encoding', title: '编码', unresize: true, sort: true}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#postgresql-database-list-control', width: 150}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '暂无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(postgresql-database-list)', function (obj) {
|
||||
if (obj.event === 'add_database') {
|
||||
admin.popup({
|
||||
title: '新建数据库'
|
||||
, area: ['600px', '300px']
|
||||
, id: 'LAY-popup-postgresql-database-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/postgresql15/add_database', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-postgresql-database-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(postgresql-database-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('高风险操作,确定要删除数据库 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除数据库 <b style="color: red;">' + data.name + '</b> ...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/deleteDatabase"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
database: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('数据库' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'backup') {
|
||||
// 打开备份页面
|
||||
admin.popup({
|
||||
title: '备份管理 - ' + data.name
|
||||
, area: ['70%', '80%']
|
||||
, id: 'LAY-popup-postgresql-backup'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('plugins/postgresql15/backup', {
|
||||
data: data
|
||||
}).done(function () {
|
||||
form.render(null, 'LAY-popup-postgresql-backup');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据库用户列表
|
||||
table.render({
|
||||
elem: '#postgresql-user-list'
|
||||
, url: '/api/plugins/postgresql15/user'
|
||||
, toolbar: '#postgresql-user-list-bar'
|
||||
, title: '用户列表'
|
||||
, cols: [[
|
||||
{field: 'user', title: '用户名', fixed: 'left', width: 300, sort: true}
|
||||
, {field: 'role', title: '权限'}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#postgresql-user-list-control', width: 150}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '暂无数据'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(postgresql-user-list)', function (obj) {
|
||||
if (obj.event === 'add_user') {
|
||||
admin.popup({
|
||||
title: '新建用户'
|
||||
, area: ['600px', '300px']
|
||||
, id: 'LAY-popup-postgresql-user-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/postgresql15/add_user', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-postgresql-user-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(postgresql-user-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('高风险操作,确定要删除用户 <b style="color: red;">' + data.user + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除用户 <b style="color: red;">' + data.user + '</b> ...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/deleteUser"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('用户' + data.user + '删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'change_password') {
|
||||
// 弹出输入密码框
|
||||
layer.prompt({
|
||||
formType: 1
|
||||
, title: '请输入新密码(建议8位以上大小写数字特殊符号混合)'
|
||||
}, function (value, index) {
|
||||
layer.close(index);
|
||||
layer.msg('正在修改密码 ...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
// 发送请求
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/changePassword"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
user: data.user,
|
||||
password: value
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('用户' + data.user + '密码修改成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql日志并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/log"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#postgresql-log').text('PostgreSQL日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#postgresql-log'
|
||||
, title: 'error.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#postgresql-log').text(result.data);
|
||||
code({
|
||||
elem: '#postgresql-log'
|
||||
, title: 'postgresql.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#postgresql-config-editor').text(result.data);
|
||||
postgresql_config_editor = ace.edit("postgresql-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql用户配置并渲染
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/userConfig"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#postgresql-user-config-editor').text(result.data);
|
||||
postgresql_user_config_editor = ace.edit("postgresql-user-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取postgresql负载状态并渲染
|
||||
table.render({
|
||||
elem: '#postgresql-load-status'
|
||||
, url: '/api/plugins/postgresql15/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '80%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 事件监听
|
||||
$('#postgresql-start').click(function () {
|
||||
layer.confirm('确定要启动PostgreSQL吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在启动PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#postgresql-stop').click(function () {
|
||||
layer.confirm('停止PostgreSQL将导致使用PostgreSQL的网站无法访问,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#postgresql-restart').click(function () {
|
||||
layer.confirm('重启PostgreSQL将导致使用PostgreSQL的网站短时间无法访问,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#postgresql-reload').click(function () {
|
||||
index = layer.msg('正在重载PostgreSQL...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('PostgreSQL重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#postgresql-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: postgresql_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PostgreSQL配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#postgresql-user-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
, shade: 0.3
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/userConfig"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: postgresql_user_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('PostgreSQL用户配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,77 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器 - 添加数据库
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-postgresql-database-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数据库名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="database" lay-verify="required" placeholder="请输入数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" lay-verify="required" placeholder="请输入密码(8位以上大小写数字特殊符号混合)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-postgresql-database-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'table'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-postgresql-database-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/addDatabase"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
table.reload('postgresql-database-list');
|
||||
table.reload('postgresql-user-list');
|
||||
layer.alert('数据库添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,79 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器 - 添加用户
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-postgresql-user-form">
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" lay-verify="required"
|
||||
placeholder="请输入密码(8位以上大小写数字特殊符号混合)"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数据库</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="database" lay-verify="required" placeholder="输入授权给该用户的数据库名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="add-postgresql-user-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'table'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table
|
||||
|
||||
form.render();
|
||||
|
||||
// 提交
|
||||
form.on('submit(add-postgresql-user-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/addUser"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
table.reload('postgresql-database-list');
|
||||
table.reload('postgresql-user-list');
|
||||
layer.alert('用户添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,141 @@
|
||||
<!--
|
||||
Name: PostgreSQL管理器 - 数据库备份
|
||||
Author: 耗子
|
||||
Date: 2023-08-13
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs12 layui-col-sm12 layui-col-md12">
|
||||
<table class="layui-hide" id="postgresql-backup-list" lay-filter="postgresql-backup-list"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份顶部工具栏 -->
|
||||
<script type="text/html" id="postgresql-database-backup-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="backup_database">备份数据库</button>
|
||||
<button class="layui-btn layui-btn-sm" id="upload_postgresql_backup">上传备份</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 备份右侧管理 -->
|
||||
<script type="text/html" id="postgresql-database-backup-control">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'laydate', 'code'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, table = layui.table
|
||||
, upload = layui.upload;
|
||||
|
||||
// 渲染表格
|
||||
table.render({
|
||||
elem: '#postgresql-backup-list'
|
||||
, url: '/api/plugins/postgresql15/backup'
|
||||
, toolbar: '#postgresql-database-backup-bar'
|
||||
, title: '备份列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '备份名称', width: 500}
|
||||
, {field: 'size', title: '文件大小'}
|
||||
, {field: 'right', title: '操作', width: 150, toolbar: '#postgresql-database-backup-control'}
|
||||
]]
|
||||
, text: {
|
||||
none: '无备份数据'
|
||||
}
|
||||
, done: function (res, curr, count) {
|
||||
upload.render({
|
||||
elem: '#upload_postgresql_backup'
|
||||
, url: '/api/plugins/postgresql15/uploadBackup'
|
||||
, accept: 'file'
|
||||
, ext: 'sql|zip|rar|tar|gz|bz2'
|
||||
, before: function (obj) {
|
||||
index = layer.msg('正在上传备份文件,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
}
|
||||
, done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg('上传成功!', {icon: 1});
|
||||
table.reload('postgresql-backup-list');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(postgresql-backup-list)', function (obj) {
|
||||
if (obj.event === 'backup_database') {
|
||||
index = layer.msg('正在备份数据库,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: '/api/plugins/postgresql15/createBackup'
|
||||
, type: 'post'
|
||||
, data: {
|
||||
database: params.data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.alert('备份失败!');
|
||||
return false;
|
||||
}
|
||||
table.reload('postgresql-backup-list');
|
||||
layer.msg('备份成功!', {icon: 1});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(postgresql-backup-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除数据库备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在删除数据库备份,请稍等...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/deleteBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('数据库备份删除失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('数据库备份' + data.name + '删除成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'restore') {
|
||||
layer.confirm('高风险操作,确定要恢复数据库备份 <b style="color: red;">' + data.name + '</b> 吗?', function (index) {
|
||||
index = layer.msg('正在恢复数据库备份,可能需要较长时间,请勿操作...', {
|
||||
icon: 16
|
||||
, time: 0
|
||||
});
|
||||
data.database = params.data.name;
|
||||
admin.req({
|
||||
url: "/api/plugins/postgresql15/restoreBackup"
|
||||
, type: 'post'
|
||||
, data: data
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
layer.msg('数据库备份恢复失败,请刷新重试!')
|
||||
return false;
|
||||
}
|
||||
layer.alert('数据库备份' + data.name + '恢复成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,190 @@
|
||||
<!--
|
||||
Name: Redis管理器
|
||||
Author: 耗子
|
||||
Date: 2023-08-09
|
||||
-->
|
||||
<title>Redis</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">Redis 管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">运行状态</li>
|
||||
<li>配置修改</li>
|
||||
<li>负载状态</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<blockquote id="redis-status" class="layui-elem-quote layui-quote-nm">当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="redis-start" class="layui-btn">启动</button>
|
||||
<button id="redis-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="redis-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="redis-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是Redis主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="redis-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="redis-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="redis-load-status"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let redis_config_editor;
|
||||
layui.use(['admin', 'jquery', 'element', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, element = layui.element
|
||||
, table = layui.table;
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#redis-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#redis-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#redis-config-editor').text(result.data);
|
||||
redis_config_editor = ace.edit("redis-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: '#redis-load-status'
|
||||
, url: '/api/plugins/redis/load'
|
||||
, cols: [[
|
||||
{field: 'name', width: '80%', title: '属性',}
|
||||
, {field: 'value', width: '20%', title: '当前值'}
|
||||
]]
|
||||
});
|
||||
element.render();
|
||||
|
||||
// 事件监听
|
||||
$('#redis-start').click(function () {
|
||||
layer.confirm('确定要启动Redis吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在启动Redis,请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Redis启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#redis-stop').click(function () {
|
||||
layer.confirm('停止Redis可能导致使用Redis的网站出现异常,是否继续停止?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止Redis,请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Redis停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#redis-restart').click(function () {
|
||||
layer.confirm('重启Redis将导致使用Redis的网站短时间出现异常,是否继续重启?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启Redis,请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Redis重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#redis-reload').click(function () {
|
||||
index = layer.msg('正在重载Redis,请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('Redis重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#redis-config-save').click(function () {
|
||||
index = layer.msg('正在保存Redis配置,请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/redis/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: redis_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('Redis配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,302 @@
|
||||
<!--
|
||||
Name: 系统工具箱
|
||||
-->
|
||||
<title>系统工具箱</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">系统工具箱</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">DNS</li>
|
||||
<li>SWAP</li>
|
||||
<li>Hosts</li>
|
||||
<li>时区</li>
|
||||
<li>Root密码</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<div class="layui-form" lay-filter="toolbox-dns">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">DNS 1</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="dns1" value="获取中ing..."
|
||||
class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改 DNS 1</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">DNS 2</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="dns2" value="获取中ing..."
|
||||
class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改 DNS 2</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="toolbox-dns-submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
总共:
|
||||
<span class="layui-badge layui-bg-blue"
|
||||
id="toolbox-swap-total">获取中...</span>
|
||||
</blockquote>
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
已用:
|
||||
<span class="layui-badge" id="toolbox-swap-used">获取中...</span>
|
||||
</blockquote>
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
可用:
|
||||
<span class="layui-badge layui-bg-green"
|
||||
id="toolbox-swap-free">获取中...</span>
|
||||
</blockquote>
|
||||
<div class="layui-form" lay-filter="toolbox-swap">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">SWAP 大小</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="swap" value="获取中ing..."
|
||||
class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">MB</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="toolbox-swap-submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是 /etc/hosts 文件。<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="toolbox-hosts-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="toolbox-hosts-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-form" lay-filter="toolbox-timezone">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">时区</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template lay-url="/api/plugins/toolbox/timezone"
|
||||
lay-done="layui.data.done(d);">
|
||||
<select name="timezone">
|
||||
{{# layui.each(d.data.zones, function(index, item){ }}
|
||||
{{# if(item == d.data.zone){ }}
|
||||
<option value="{{ item }}" selected="">{{ item }}</option>
|
||||
{{# }else{ }}
|
||||
<option value="{{ item }}">{{ item }}</option>
|
||||
{{# } }}
|
||||
{{# }); }}
|
||||
</select>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">选择一个时区</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="toolbox-timezone-submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-form" lay-filter="toolbox-root-password">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="font-size: 13px;">root 密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="password" value=""
|
||||
class="layui-input" lay-verify="required">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">修改 root 密码</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit
|
||||
lay-filter="toolbox-root-password-submit">确认修改
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let toolbox_hosts_editor;
|
||||
layui.use(['jquery', 'admin', 'view', 'form'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, form = layui.form;
|
||||
|
||||
form.render();
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/dns"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
form.val('toolbox-dns', {
|
||||
"dns1": result.data[0]
|
||||
, "dns2": result.data[1]
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
form.on('submit(toolbox-dns-submit)', function (data) {
|
||||
index = layer.msg('正在修改DNS...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/dns"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('DNS修改成功!');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/swap"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#toolbox-swap-total').html(result.data.total);
|
||||
$('#toolbox-swap-used').html(result.data.used);
|
||||
$('#toolbox-swap-free').html(result.data.free);
|
||||
form.val('toolbox-swap', {
|
||||
"swap": result.data.size
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
form.on('submit(toolbox-swap-submit)', function (data) {
|
||||
index = layer.msg('正在修改SWAP...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/swap"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
size: data.field.swap
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('SWAP修改成功!');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/hosts"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#toolbox-hosts-editor').text(result.data);
|
||||
toolbox_hosts_editor = ace.edit("toolbox-hosts-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
$('#toolbox-hosts-save').click(function () {
|
||||
index = layer.msg('正在保存Hosts...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/hosts"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
hosts: toolbox_hosts_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('Hosts保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
form.on('submit(toolbox-root-password-submit)', function (data) {
|
||||
index = layer.msg('正在修改root密码...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/rootPassword"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('root密码修改成功!');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
layui.data.done = function (d) {
|
||||
layui.use(['form', 'admin'], function () {
|
||||
let form = layui.form,
|
||||
admin = layui.admin;
|
||||
form.render(null, 'toolbox-timezone');
|
||||
form.on('submit(toolbox-timezone-submit)', function (data) {
|
||||
index = layer.msg('正在修改时区...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/toolbox/timezone"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index)
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('时区修改成功!');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -316,6 +316,15 @@ Date: 2023-07-24
|
||||
let domains = $("input[name='domains[]']").map(function () {
|
||||
return $(this).val();
|
||||
}).get()
|
||||
var reg = new RegExp(/\n443.*\n?/);
|
||||
// 如果开启了https,就自动添加443端口
|
||||
if ($('input[name="ssl"]').prop('checked') && !reg.test(ports)) {
|
||||
ports = ports + '\n443 ssl http2';
|
||||
}
|
||||
// 如果关闭了https,就自动删除443端口
|
||||
if (!$('input[name="ssl"]').prop('checked') && reg.test(ports)) {
|
||||
ports = ports.replace(/443.*\n?/, '');
|
||||
}
|
||||
|
||||
admin.req({
|
||||
url: '/api/panel/website/config'
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base"
|
||||
],
|
||||
"labels": [
|
||||
"🤖 Dependencies"
|
||||
],
|
||||
"commitMessagePrefix": "chore(deps): ",
|
||||
"customEnvVariables": {
|
||||
"GOPROXY": "https://goproxy.cn,direct"
|
||||
},
|
||||
"postUpdateOptions": [
|
||||
"gomodTidy"
|
||||
]
|
||||
}
|
||||
@@ -13,9 +13,12 @@ import (
|
||||
"panel/app/http/controllers/plugins/php81"
|
||||
"panel/app/http/controllers/plugins/php82"
|
||||
"panel/app/http/controllers/plugins/phpmyadmin"
|
||||
"panel/app/http/controllers/plugins/postgresql15"
|
||||
"panel/app/http/controllers/plugins/pureftpd"
|
||||
"panel/app/http/controllers/plugins/redis"
|
||||
"panel/app/http/controllers/plugins/s3fs"
|
||||
"panel/app/http/controllers/plugins/supervisor"
|
||||
"panel/app/http/controllers/plugins/toolbox"
|
||||
"panel/app/http/middleware"
|
||||
)
|
||||
|
||||
@@ -94,6 +97,33 @@ func Plugin() {
|
||||
route.Post("userPassword", mysql80Controller.SetUserPassword)
|
||||
route.Post("userPrivileges", mysql80Controller.SetUserPrivileges)
|
||||
})
|
||||
facades.Route().Prefix("api/plugins/postgresql15").Middleware(middleware.Jwt()).Group(func(route route.Route) {
|
||||
postgresql15Controller := postgresql15.NewPostgresql15Controller()
|
||||
route.Get("status", postgresql15Controller.Status)
|
||||
route.Post("reload", postgresql15Controller.Reload)
|
||||
route.Post("start", postgresql15Controller.Start)
|
||||
route.Post("stop", postgresql15Controller.Stop)
|
||||
route.Post("restart", postgresql15Controller.Restart)
|
||||
route.Get("load", postgresql15Controller.Load)
|
||||
route.Get("config", postgresql15Controller.GetConfig)
|
||||
route.Post("config", postgresql15Controller.SaveConfig)
|
||||
route.Get("userConfig", postgresql15Controller.GetUserConfig)
|
||||
route.Post("userConfig", postgresql15Controller.SaveUserConfig)
|
||||
route.Get("log", postgresql15Controller.Log)
|
||||
route.Post("clearLog", postgresql15Controller.ClearLog)
|
||||
route.Get("database", postgresql15Controller.DatabaseList)
|
||||
route.Post("addDatabase", postgresql15Controller.AddDatabase)
|
||||
route.Post("deleteDatabase", postgresql15Controller.DeleteDatabase)
|
||||
route.Get("backup", postgresql15Controller.BackupList)
|
||||
route.Post("createBackup", postgresql15Controller.CreateBackup)
|
||||
route.Post("uploadBackup", postgresql15Controller.UploadBackup)
|
||||
route.Post("deleteBackup", postgresql15Controller.DeleteBackup)
|
||||
route.Post("restoreBackup", postgresql15Controller.RestoreBackup)
|
||||
route.Get("user", postgresql15Controller.UserList)
|
||||
route.Post("addUser", postgresql15Controller.AddUser)
|
||||
route.Post("deleteUser", postgresql15Controller.DeleteUser)
|
||||
route.Post("userPassword", postgresql15Controller.SetUserPassword)
|
||||
})
|
||||
facades.Route().Prefix("api/plugins/php74").Middleware(middleware.Jwt()).Group(func(route route.Route) {
|
||||
php74Controller := php74.NewPhp74Controller()
|
||||
route.Get("status", php74Controller.Status)
|
||||
@@ -185,6 +215,17 @@ func Plugin() {
|
||||
route.Get("port", pureFtpdController.GetPort)
|
||||
route.Post("port", pureFtpdController.SetPort)
|
||||
})
|
||||
facades.Route().Prefix("api/plugins/redis").Middleware(middleware.Jwt()).Group(func(route route.Route) {
|
||||
redisController := redis.NewRedisController()
|
||||
route.Get("status", redisController.Status)
|
||||
route.Post("reload", redisController.Reload)
|
||||
route.Post("start", redisController.Start)
|
||||
route.Post("stop", redisController.Stop)
|
||||
route.Post("restart", redisController.Restart)
|
||||
route.Get("load", redisController.Load)
|
||||
route.Get("config", redisController.GetConfig)
|
||||
route.Post("config", redisController.SaveConfig)
|
||||
})
|
||||
facades.Route().Prefix("api/plugins/s3fs").Middleware(middleware.Jwt()).Group(func(route route.Route) {
|
||||
s3fsController := s3fs.NewS3fsController()
|
||||
route.Get("list", s3fsController.List)
|
||||
@@ -229,4 +270,16 @@ func Plugin() {
|
||||
route.Post("whiteList", fail2banController.SetWhiteList)
|
||||
route.Get("whiteList", fail2banController.GetWhiteList)
|
||||
})
|
||||
facades.Route().Prefix("api/plugins/toolbox").Middleware(middleware.Jwt()).Group(func(route route.Route) {
|
||||
toolboxController := toolbox.NewToolBoxController()
|
||||
route.Get("dns", toolboxController.GetDNS)
|
||||
route.Post("dns", toolboxController.SetDNS)
|
||||
route.Get("swap", toolboxController.GetSWAP)
|
||||
route.Post("swap", toolboxController.SetSWAP)
|
||||
route.Get("timezone", toolboxController.GetTimezone)
|
||||
route.Post("timezone", toolboxController.SetTimezone)
|
||||
route.Get("hosts", toolboxController.GetHosts)
|
||||
route.Post("hosts", toolboxController.SetHosts)
|
||||
route.Post("rootPassword", toolboxController.SetRootPassword)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -63,8 +63,7 @@ Prepare_system() {
|
||||
useradd -s /sbin/nologin -g www www
|
||||
fi
|
||||
|
||||
rm -rf /etc/localtime
|
||||
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
timedatectl set-timezone Asia/Shanghai
|
||||
|
||||
[ -s /etc/selinux/config ] && sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
|
||||
setenforce 0 > /dev/null 2>&1
|
||||
|
||||
@@ -288,7 +288,79 @@ ${mysqlPath}/bin/mysqld --initialize-insecure --user=mysql --basedir=${mysqlPath
|
||||
echo "export PATH=${mysqlPath}/bin:\$PATH" >> /etc/profile
|
||||
source /etc/profile
|
||||
|
||||
# 启动
|
||||
# ARM 环境下,没有 systemd 文件
|
||||
if [ "${ARCH}" == "aarch64" ]; then
|
||||
mkdir -p ${mysqlPath}/lib/systemd/system
|
||||
cat > ${mysqlPath}/lib/systemd/system/mysqld.service << EOF
|
||||
# Copyright (c) 2015, 2023, Oracle and/or its affiliates.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License, version 2.0,
|
||||
# as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is also distributed with certain software (including
|
||||
# but not limited to OpenSSL) that is licensed under separate terms,
|
||||
# as designated in a particular file or component or in included license
|
||||
# documentation. The authors of MySQL hereby grant you an additional
|
||||
# permission to link the program and your derivative works with the
|
||||
# separately licensed software that they have included with MySQL.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License, version 2.0, for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# systemd service file for MySQL forking server
|
||||
#
|
||||
|
||||
[Unit]
|
||||
Description=MySQL Server
|
||||
Documentation=man:mysqld(8)
|
||||
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
|
||||
After=network.target
|
||||
After=syslog.target
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
[Service]
|
||||
User=mysql
|
||||
Group=mysql
|
||||
|
||||
Type=forking
|
||||
|
||||
PIDFile=/www/server/mysql/mysqld.pid
|
||||
|
||||
# Disable service start and stop timeout logic of systemd for mysqld service.
|
||||
TimeoutSec=0
|
||||
|
||||
# Execute pre and post scripts as root
|
||||
PermissionsStartOnly=true
|
||||
|
||||
# Needed to create system tables
|
||||
ExecStartPre=/www/server/mysql/bin/mysqld_pre_systemd
|
||||
|
||||
# Start main service
|
||||
ExecStart=/www/server/mysql/bin/mysqld --daemonize --pid-file=/www/server/mysql/mysqld.pid $MYSQLD_OPTS
|
||||
|
||||
# Use this to switch malloc implementation
|
||||
EnvironmentFile=-/etc/sysconfig/mysql
|
||||
|
||||
# Sets open_files_limit
|
||||
LimitNOFILE = 5000
|
||||
|
||||
Restart=on-failure
|
||||
|
||||
RestartPreventExitStatus=1
|
||||
|
||||
PrivateTmp=false
|
||||
EOF
|
||||
fi
|
||||
|
||||
cp ${mysqlPath}/lib/systemd/system/mysqld.service /etc/systemd/system/mysqld.service
|
||||
sed -i '/ExecStartPre/d' /etc/systemd/system/mysqld.service
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } ||
|
||||
downloadUrl="https://dl.cdn.haozi.net/panel/openresty"
|
||||
setupPath="/www"
|
||||
openrestyPath="${setupPath}/server/openresty"
|
||||
openrestyVersion="1.21.4.1"
|
||||
openrestyVersion="1.21.4.2"
|
||||
cpuCore=$(cat /proc/cpuinfo | grep "processor" | wc -l)
|
||||
ipLocation=$(curl -s https://ip.ping0.cc/geo)
|
||||
|
||||
@@ -380,7 +380,7 @@ EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable openresty.service
|
||||
systemctl start openresty.service
|
||||
systemctl restart openresty.service
|
||||
|
||||
panel writePlugin openresty ${openrestyVersion}
|
||||
|
||||
|
||||
@@ -223,8 +223,8 @@ sed -i 's/display_errors = Off/display_errors = On/g' ${phpPath}/etc/php.ini
|
||||
sed -i 's/error_reporting =.*/error_reporting = E_ALL \& \~E_NOTICE/g' ${phpPath}/etc/php.ini
|
||||
|
||||
# 设置SSL根证书
|
||||
sed -i "s#;openssl.cafile=#openssl.cafile=/etc/pki/tls/certs/ca-bundle.crt#" ${phpPath}/etc/php.ini
|
||||
sed -i "s#;curl.cainfo =#curl.cainfo = /etc/pki/tls/certs/ca-bundle.crt#" ${phpPath}/etc/php.ini
|
||||
#sed -i "s#;openssl.cafile=#openssl.cafile=/etc/pki/tls/certs/ca-bundle.crt#" ${phpPath}/etc/php.ini
|
||||
#sed -i "s#;curl.cainfo =#curl.cainfo = /etc/pki/tls/certs/ca-bundle.crt#" ${phpPath}/etc/php.ini
|
||||
|
||||
# 关闭php外显
|
||||
sed -i 's/expose_php = On/expose_php = Off/g' ${phpPath}/etc/php.ini
|
||||
|
||||
@@ -33,7 +33,7 @@ Install() {
|
||||
|
||||
cd /www/server/php/${phpVersion}/src/ext/pdo_pgsql
|
||||
/www/server/php/${phpVersion}/bin/phpize
|
||||
./configure --with-php-config=/www/server/php/${phpVersion}/bin/php-config --with-pdo-pgsql=/usr/pgsql-15
|
||||
./configure --with-php-config=/www/server/php/${phpVersion}/bin/php-config --with-pdo-pgsql=/www/server/postgresql
|
||||
make
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
|
||||
@@ -36,7 +36,7 @@ Install() {
|
||||
cd /www/server/php/${phpVersion}/src/ext
|
||||
rm -rf phpredis
|
||||
rm -rf phpredis.tar.gz
|
||||
wget -O phpredis.tar.gz ${downloadUrl}/php-ext/phpredis-${phpredisVersion}.tar.gz
|
||||
wget -O phpredis.tar.gz ${downloadUrl}/phpredis-${phpredisVersion}.tar.gz
|
||||
tar -zxvf phpredis.tar.gz
|
||||
mv phpredis-${phpredisVersion} phpredis
|
||||
cd phpredis
|
||||
|
||||
@@ -18,10 +18,154 @@ limitations under the License.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
postgresqlVersion="$1"
|
||||
setup_Path="/www"
|
||||
postgresqlPath="${setup_Path}/server/postgresql"
|
||||
os_Version=$(cat /etc/redhat-release | sed -r 's/.* ([0-9]+)\.?.*/\1/')
|
||||
ipLocation=$(curl -s https://ip.ping0.cc/geo)
|
||||
ARCH=$(uname -m)
|
||||
memTotal=$(LC_ALL=C free -m | grep Mem | awk '{print $2}')
|
||||
OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } || { [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]] && echo "centos"; } || echo "unknown")
|
||||
downloadUrl="https://dl.cdn.haozi.net/panel/postgresql"
|
||||
setupPath="/www"
|
||||
postgresqlPath="${setupPath}/server/postgresql"
|
||||
postgresqlVersion=""
|
||||
postgresqlPassword=$(cat /dev/urandom | head -n 16 | md5sum | head -c 16)
|
||||
cpuCore=$(cat /proc/cpuinfo | grep "processor" | wc -l)
|
||||
|
||||
# TODO
|
||||
if [[ "${1}" == "15" ]]; then
|
||||
postgresqlVersion="15.3"
|
||||
else
|
||||
echo -e $HR
|
||||
echo "错误:不支持的 PostgreSQL 版本!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 安装依赖
|
||||
if [ "${OS}" == "centos" ]; then
|
||||
dnf makecache -y
|
||||
dnf groupinstall "Development Tools" -y
|
||||
dnf install make gettext zlib-devel readline-devel libicu-devel libxml2-devel libxslt-devel openssl-devel systemd-devel -y
|
||||
elif [ "${OS}" == "debian" ]; then
|
||||
apt update
|
||||
apt install build-essential make gettext zlib1g-dev libreadline-dev libicu-dev libxml2-dev libxslt-dev libssl-dev libsystemd-dev -y
|
||||
else
|
||||
echo -e $HR
|
||||
echo "错误:耗子Linux面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
postgresqlUserCheck=$(cat /etc/passwd | grep postgres)
|
||||
if [ "${postgresqlUserCheck}" == "" ]; then
|
||||
groupadd postgres
|
||||
useradd -g postgres postgres
|
||||
fi
|
||||
|
||||
# 准备目录
|
||||
rm -rf ${postgresqlPath}
|
||||
mkdir -p ${postgresqlPath}
|
||||
cd ${postgresqlPath}
|
||||
|
||||
# 下载源码
|
||||
wget -T 120 -O ${postgresqlPath}/postgresql-${postgresqlVersion}.tar.gz ${downloadUrl}/postgresql-${postgresqlVersion}.tar.gz
|
||||
tar -zxvf postgresql-${postgresqlVersion}.tar.gz
|
||||
rm -f postgresql-${postgresqlVersion}.tar.gz
|
||||
mv postgresql-${postgresqlVersion} src
|
||||
|
||||
# 编译
|
||||
cd src
|
||||
./configure --prefix=${postgresqlPath} --enable-nls='zh_CN en' --with-icu --with-ssl=openssl --with-systemd --with-libxml --with-libxslt
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:PostgreSQL 编译初始化失败,请截图错误信息寻求帮助。"
|
||||
rm -rf ${postgresqlPath}
|
||||
exit 1
|
||||
fi
|
||||
make -j${cpuCore}
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:PostgreSQL 编译失败,请截图错误信息寻求帮助。"
|
||||
rm -rf ${postgresqlPath}
|
||||
exit 1
|
||||
fi
|
||||
make install
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:PostgreSQL 安装失败,请截图错误信息寻求帮助。"
|
||||
rm -rf ${postgresqlPath}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf ${postgresqlPath}/src
|
||||
|
||||
# 配置
|
||||
mkdir -p ${postgresqlPath}/data
|
||||
mkdir -p ${postgresqlPath}/logs
|
||||
chown -R postgres:postgres ${postgresqlPath}
|
||||
chmod -R 700 ${postgresqlPath}
|
||||
|
||||
echo "export PATH=${postgresqlPath}/bin:\$PATH" >> /etc/profile
|
||||
source /etc/profile
|
||||
|
||||
mkdir -p /home/postgres
|
||||
cd /home/postgres
|
||||
if [ -f /home/postgres/.bash_profile ]; then
|
||||
echo "export PGHOME=${postgresqlPath}" >> /home/postgres/.bash_profile
|
||||
echo "export PGDATA=${postgresqlPath}/data" >> /home/postgres/.bash_profile
|
||||
echo "export PATH=${postgresqlPath}/bin:\$PATH " >> /home/postgres/.bash_profile
|
||||
echo "MANPATH=$PGHOME/share/man:$MANPATH" >> /home/postgres/.bash_profile
|
||||
echo "LD_LIBRARY_PATH=$PGHOME/lib:$LD_LIBRARY_PATH" >> /home/postgres/.bash_profile
|
||||
source /home/postgres/.bash_profile
|
||||
fi
|
||||
if [ -f /home/postgres/.profile ]; then
|
||||
echo "export PGHOME=${postgresqlPath}" >> /home/postgres/.profile
|
||||
echo "export PGDATA=${postgresqlPath}/data" >> /home/postgres/.profile
|
||||
echo "export PATH=${postgresqlPath}/bin:\$PATH " >> /home/postgres/.profile
|
||||
echo "MANPATH=$PGHOME/share/man:$MANPATH" >> /home/postgres/.profile
|
||||
echo "LD_LIBRARY_PATH=$PGHOME/lib:$LD_LIBRARY_PATH" >> /home/postgres/.profile
|
||||
source /home/postgres/.profile
|
||||
fi
|
||||
|
||||
# 初始化
|
||||
su - postgres -c "${postgresqlPath}/bin/initdb -D ${postgresqlPath}/data"
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:PostgreSQL 初始化失败,请截图错误信息寻求帮助。"
|
||||
rm -rf ${postgresqlPath}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 配置慢查询日志
|
||||
cat >> ${postgresqlPath}/data/postgresql.conf << EOF
|
||||
logging_collector = on
|
||||
log_destination = 'stderr'
|
||||
log_directory = '${postgresqlPath}/logs'
|
||||
log_filename = 'postgresql-%Y-%m-%d.log'
|
||||
log_statement = all
|
||||
log_min_duration_statement = 5000
|
||||
EOF
|
||||
|
||||
# 写入服务
|
||||
cat > /etc/systemd/system/postgresql.service << EOF
|
||||
[Unit]
|
||||
Description=PostgreSQL database server
|
||||
Documentation=man:postgres(1)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
User=postgres
|
||||
ExecStart=${postgresqlPath}/bin/postgres -D ${postgresqlPath}/data
|
||||
ExecReload=/bin/kill -HUP \$MAINPID
|
||||
KillMode=mixed
|
||||
KillSignal=SIGINT
|
||||
TimeoutSec=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# 启动服务
|
||||
systemctl daemon-reload
|
||||
systemctl enable postgresql
|
||||
systemctl start postgresql
|
||||
|
||||
panel writePlugin postgresql${1} ${postgresqlVersion}
|
||||
|
||||
echo -e "${HR}\nPostgreSQL-${1} 安装完成\n${HR}"
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
: '
|
||||
Copyright 2022 HaoZi Technology Co., Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
|
||||
systemctl stop postgresql
|
||||
systemctl disable postgresql
|
||||
rm -rf /etc/systemd/system/postgresql.service
|
||||
systemctl daemon-reload
|
||||
pkill -9 postgresql
|
||||
rm -rf /www/server/postgresql
|
||||
|
||||
userdel -r postgres
|
||||
groupdel postgres
|
||||
|
||||
sed -i '/export PATH=\/www\/server\/postgresql/d' /etc/profile
|
||||
source /etc/profile
|
||||
|
||||
panel deletePlugin postgresql${1}
|
||||
|
||||
echo -e "${HR}\nPostgreSQL-${1} 卸载完成\n${HR}"
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
#!/bin/bash
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
: '
|
||||
Copyright 2022 HaoZi Technology Co., Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
ARCH=$(uname -m)
|
||||
OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } || { [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]] && echo "centos"; } || echo "unknown")
|
||||
downloadUrl="https://dl.cdn.haozi.net/panel/redis"
|
||||
setupPath="/www"
|
||||
redisPath="${setupPath}/server/redis"
|
||||
redisVersion="7.0.12"
|
||||
cpuCore=$(cat /proc/cpuinfo | grep "processor" | wc -l)
|
||||
|
||||
if ! id -u "redis" > /dev/null 2>&1; then
|
||||
groupadd redis
|
||||
useradd -s /sbin/nologin -g redis redis
|
||||
fi
|
||||
|
||||
# 安装依赖
|
||||
if [ "${OS}" == "centos" ]; then
|
||||
dnf makecache -y
|
||||
dnf groupinstall "Development Tools" -y
|
||||
dnf install systemd-devel openssl-devel -y
|
||||
elif [ "${OS}" == "debian" ]; then
|
||||
apt update
|
||||
apt install build-essential libsystemd-dev libssl-dev -y
|
||||
else
|
||||
echo -e $HR
|
||||
echo "错误:耗子Linux面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 准备目录
|
||||
rm -rf ${redisPath}
|
||||
mkdir -p ${redisPath}
|
||||
cd ${redisPath}
|
||||
|
||||
# 下载源码
|
||||
wget -T 120 -O ${redisPath}/redis-${redisVersion}.tar.gz ${downloadUrl}/redis-${redisVersion}.tar.gz
|
||||
tar -zxvf redis-${redisVersion}.tar.gz
|
||||
rm -f redis-${redisVersion}.tar.gz
|
||||
mv redis-${redisVersion}/* ./ && rm -rf redis-${redisVersion}
|
||||
mkdir -p ${redisPath}/bin
|
||||
|
||||
make BUILD_TLS=yes USE_SYSTEMD=yes -j${cpuCore}
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:Redis编译失败,请截图错误信息寻求帮助。"
|
||||
rm -rf ${redisPath}
|
||||
exit 1
|
||||
fi
|
||||
make PREFIX=${redisPath} install
|
||||
if [ ! -f "${redisPath}/bin/redis-server" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:Redis安装失败,请截图错误信息寻求帮助。"
|
||||
rm -rf ${redisPath}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 设置软链接
|
||||
ln -sf ${redisPath}/bin/redis-cli /usr/bin/redis-cli
|
||||
ln -sf ${redisPath}/bin/redis-server /usr/bin/redis-server
|
||||
ln -sf ${redisPath}/bin/redis-sentinel /usr/bin/redis-sentinel
|
||||
ln -sf ${redisPath}/bin/redis-benchmark /usr/bin/redis-benchmark
|
||||
ln -sf ${redisPath}/bin/redis-check-aof /usr/bin/redis-check-aof
|
||||
ln -sf ${redisPath}/bin/redis-check-rdb /usr/bin/redis-check-rdb
|
||||
|
||||
# 设置配置文件
|
||||
VM_OVERCOMMIT_MEMORY=$(cat /etc/sysctl.conf|grep vm.overcommit_memory)
|
||||
NET_CORE_SOMAXCONN=$(cat /etc/sysctl.conf|grep net.core.somaxconn)
|
||||
if [ -z "${VM_OVERCOMMIT_MEMORY}" ] && [ -z "${NET_CORE_SOMAXCONN}" ];then
|
||||
echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf
|
||||
echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf
|
||||
sysctl -p
|
||||
fi
|
||||
|
||||
sed -i 's/dir .\//dir \/www\/server\/redis\//g' ${redisPath}/redis.conf
|
||||
sed -i 's/# supervised.*/supervised systemd/g' ${redisPath}/redis.conf
|
||||
sed -i 's/daemonize.*/daemonize no/g' ${redisPath}/redis.conf
|
||||
|
||||
if [ "${ARCH}" == "aarch64" ]; then
|
||||
echo "ignore-warnings ARM64-COW-BUG" >> ${redisPath}/redis.conf
|
||||
fi
|
||||
|
||||
chown -R redis:redis ${redisPath}
|
||||
chmod -R 755 ${redisPath}
|
||||
|
||||
# 设置服务
|
||||
cp -r utils/systemd-redis_server.service /etc/systemd/system/redis.service
|
||||
sed -i "s!ExecStart=.*!ExecStart=${redisPath}/bin/redis-server ${redisPath}/redis.conf!g" /etc/systemd/system/redis.service
|
||||
sed -i "s!#User=.*!User=redis!g" /etc/systemd/system/redis.service
|
||||
sed -i "s!#Group=.*!Group=redis!g" /etc/systemd/system/redis.service
|
||||
sed -i "s!#WorkingDirectory=.*!WorkingDirectory=${redisPath}!g" /etc/systemd/system/redis.service
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable redis
|
||||
systemctl start redis
|
||||
|
||||
panel writePlugin redis ${redisVersion}
|
||||
|
||||
echo -e "${HR}\nRedis 安装完成\n${HR}"
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
: '
|
||||
Copyright 2022 HaoZi Technology Co., Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
|
||||
systemctl stop redis
|
||||
systemctl disable redis
|
||||
rm -rf /etc/systemd/system/redis.service
|
||||
systemctl daemon-reload
|
||||
pkill -9 redis
|
||||
rm -rf /www/server/redis
|
||||
|
||||
rm -rf /usr/bin/redis-cli
|
||||
rm -rf /usr/bin/redis-server
|
||||
rm -rf /usr/bin/redis-benchmark
|
||||
rm -rf /usr/bin/redis-check-aof
|
||||
rm -rf /usr/bin/redis-check-rdb
|
||||
rm -rf /usr/bin/redis-sentinel
|
||||
|
||||
panel deletePlugin redis
|
||||
|
||||
echo -e "${HR}\nRedis 卸载完成\n${HR}"
|
||||
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
: '
|
||||
Copyright 2022 HaoZi Technology Co., Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
ARCH=$(uname -m)
|
||||
OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } || { [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]] && echo "centos"; } || echo "unknown")
|
||||
downloadUrl="https://dl.cdn.haozi.net/panel/redis"
|
||||
setupPath="/www"
|
||||
redisPath="${setupPath}/server/redis"
|
||||
redisVersion="7.0.12"
|
||||
cpuCore=$(cat /proc/cpuinfo | grep "processor" | wc -l)
|
||||
|
||||
# 准备目录
|
||||
cd ${redisPath}
|
||||
|
||||
# 下载源码
|
||||
wget -T 120 -O ${redisPath}/redis-${redisVersion}.tar.gz ${downloadUrl}/redis-${redisVersion}.tar.gz
|
||||
tar -zxvf redis-${redisVersion}.tar.gz
|
||||
rm -f redis-${redisVersion}.tar.gz
|
||||
mv redis-${redisVersion}/* ./ && rm -rf redis-${redisVersion}
|
||||
mkdir -p ${redisPath}/bin
|
||||
|
||||
make BUILD_TLS=yes USE_SYSTEMD=yes -j${cpuCore}
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:Redis编译失败,请截图错误信息寻求帮助。"
|
||||
rm -rf ${redisPath}
|
||||
exit 1
|
||||
fi
|
||||
make PREFIX=${redisPath} install
|
||||
if [ ! -f "${redisPath}/bin/redis-server" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:Redis安装失败,请截图错误信息寻求帮助。"
|
||||
rm -rf ${redisPath}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 设置软链接
|
||||
ln -sf ${redisPath}/bin/redis-cli /usr/bin/redis-cli
|
||||
ln -sf ${redisPath}/bin/redis-server /usr/bin/redis-server
|
||||
ln -sf ${redisPath}/bin/redis-sentinel /usr/bin/redis-sentinel
|
||||
ln -sf ${redisPath}/bin/redis-benchmark /usr/bin/redis-benchmark
|
||||
ln -sf ${redisPath}/bin/redis-check-aof /usr/bin/redis-check-aof
|
||||
ln -sf ${redisPath}/bin/redis-check-rdb /usr/bin/redis-check-rdb
|
||||
|
||||
# 设置配置文件
|
||||
sed -i 's/dir .\//dir \/www\/server\/redis\//g' ${redisPath}/redis.conf
|
||||
sed -i 's/# supervised.*/supervised systemd/g' ${redisPath}/redis.conf
|
||||
sed -i 's/daemonize.*/daemonize no/g' ${redisPath}/redis.conf
|
||||
|
||||
if [ "${ARCH}" == "aarch64" ]; then
|
||||
echo "ignore-warnings ARM64-COW-BUG" >> ${redisPath}/redis.conf
|
||||
fi
|
||||
|
||||
chown -R redis:redis ${redisPath}
|
||||
chmod -R 755 ${redisPath}
|
||||
|
||||
# 设置服务
|
||||
cp -r utils/systemd-redis_server.service /etc/systemd/system/redis.service
|
||||
sed -i "s!ExecStart=.*!ExecStart=${redisPath}/bin/redis-server ${redisPath}/redis.conf!g" /etc/systemd/system/redis.service
|
||||
sed -i "s!#User=.*!User=redis!g" /etc/systemd/system/redis.service
|
||||
sed -i "s!#Group=.*!Group=redis!g" /etc/systemd/system/redis.service
|
||||
sed -i "s!#WorkingDirectory=.*!WorkingDirectory=${redisPath}!g" /etc/systemd/system/redis.service
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl restart redis
|
||||
|
||||
panel writePlugin redis ${redisVersion}
|
||||
|
||||
echo -e "${HR}\nRedis 升级完成\n${HR}"
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
: '
|
||||
Copyright 2022 HaoZi Technology Co., Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
OldVersion=$(panel getSetting version)
|
||||
Reference in New Issue
Block a user