Compare commits

..
28 Commits
Author SHA1 Message Date
ssongliu 7145d4ca07 fix: 解决概览页流量突增问题 (#2142)
Refs #2073
2023-09-01 17:00:00 +08:00
ali-pay 9683a23fda fix: 解决侧边栏收起状态下菜单长度不一致的问题 (#2137) 2023-09-01 16:59:55 +08:00
ssongliu 5e182d84d0 feat: 防火墙支持删除系统占用端口 (#2116) 2023-09-01 16:59:35 +08:00
ssongliu 9800e7e03d fix: 1pctl 增加非 root 提示信息 (#2112)
Refs #2100
2023-09-01 16:59:30 +08:00
zhengkunwang223 cbf4f8ec36 feat: 修改应用同步方法 2023-08-31 16:21:42 +08:00
ssongliu 3e3b1f2c56 fix: 解决防火墙 ip 规则删除失败的问题 2023-08-31 15:44:11 +08:00
ssongliu e5a7f104f1 fix: 解决版本升级导致无法创建数据库的问题 (#2108) 2023-08-29 17:21:14 +08:00
Allyxandallyxmiko-server 17062da52e fix: 修复压缩包解压时可能的由于父目录不存在导致的解压失败的问题 (#2099)
Co-authored-by: allyxmiko-server <allyxmiko@gmail.com>
2023-08-29 15:50:47 +08:00
zhengkunwang 512c7daeee feat: 修改应用商店版本升级判断条件 (#2089) 2023-08-29 15:50:32 +08:00
zhengkunwang ff120c421e feat: 应用商店增加版本控制 (#2068) 2023-08-29 15:49:58 +08:00
zhengkunwang 4d5993c6ab fix: 解决打开进程守护页面报错的问题 (#2057)
Refs https://github.com/1Panel-dev/1Panel/issues/2051
2023-08-29 15:49:39 +08:00
ssongliu 627e1e3755 feat: 放开 1panel-network 按钮禁用 (#2052) 2023-08-29 15:49:33 +08:00
ssongliu 0eee2d9807 fix: 解决数据库用户名显示错误的问题 (#2028) 2023-08-22 16:33:26 +08:00
zhengkunwang f0e78c4b7c fix: 解决运行环境网站切换PHP版本导致已安装应用消失的问题 (#2026) 2023-08-22 15:42:22 +08:00
ssongliu 6da64f2c8f fix: 解决清空容器日志导致的 CPU 占用异常问题 (#2019)
Refs #1999
2023-08-22 15:42:19 +08:00
ssongliu d572c28d1c fix: 服务器地址支持设置为空 (#2016) 2023-08-22 15:42:13 +08:00
ssongliu 7fac0fcbe8 fix: 解决数据库用户名超长导致用户创建失败的问题 (#2011) 2023-08-22 15:42:09 +08:00
ssongliu cb1b6742d4 fix: 解决防火墙多端口创建失败的问题 (#1988) 2023-08-17 16:59:26 +08:00
ssongliu 27bd4a63ef fix: 延长进程状态获取等待时间 (#1986) 2023-08-17 16:11:11 +08:00
ssongliu 62d628c1aa fix: 解决进程状态一直加载中的问题 (#1983)
Refs #1968
2023-08-17 14:48:09 +08:00
ssongliu 06f81fc7f7 fix: 解决网站反代编辑时回显错误的问题 (#1980)
Refs #1976
2023-08-17 13:55:02 +08:00
wangdan-fit2cloud 23c72c8301 fix: 移动端样式优化 (#1979)
#### What this PR does / why we need it?

#### Summary of your change

#### Please indicate you've done the following:

- [ ] Made sure tests are passing and test coverage is added if needed.
- [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
2023-08-17 13:54:58 +08:00
ssongliu 280e74e01b fix: 解决 ufw 防火墙创建多端口时无法删除的问题 2023-08-17 10:21:14 +08:00
ssongliu b7dada93da fix: 解决暂停进程被重新拉起的问题 (#1977)
Refs #1964
2023-08-16 23:44:57 +08:00
ssongliu 9447936cc3 fix: 解决获取远程数据库失败的问题 (#1974)
Refs #1925
2023-08-16 23:40:55 +08:00
ssongliu 5e7429cd51 fix: 解决容器编排创建日志加载慢的问题 (#1973)
Refs #1950
2023-08-16 23:40:51 +08:00
ssongliu 7a3716a363 fix: 修改网站重定向列表样式 (#1975)
Refs #1971
2023-08-16 23:40:45 +08:00
wangdan-fit2cloud 5e38723cc1 优化移动端样式 (#1967)
#### What this PR does / why we need it?

#### Summary of your change

#### Please indicate you've done the following:

- [ ] Made sure tests are passing and test coverage is added if needed.
- [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
2023-08-16 23:40:36 +08:00
207 changed files with 3565 additions and 8098 deletions
+3 -3
View File
@@ -1,12 +1,12 @@
[README_EN.md](README_EN.md)
<p align="center"><a href="https://1panel.cn"><img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>现代化、开源的 Linux 服务器运维管理面板</b></p>
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel?color=%231890FF" alt="License: GPL v3"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel" alt="License: GPL v3"></a>
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a>
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel.svg?type=shield" alt="FOSSA Status"></a><br>
[<a href="README_EN.md">English</a>] | [<a href="README_JP.md">日本語</a>]
<a href="https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_shield"><img src="https://app.fossa.com/api/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel.svg?type=shield" alt="FOSSA Status"></a>
</p>
------------------------------
+2 -2
View File
@@ -1,11 +1,11 @@
[中文 README.md](README.md)
<p align="center"><a href="https://1panel.cn"><img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Modern and Open-Source Linux Server Operation and Management Panel</b></p>
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel" alt="License: GPL v3"></a>
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a><br>
[<a href="README.md">中文</a>] | [<a href="README_JP.md">日本語</a>]
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a>
</p>
------------------------------
-72
View File
@@ -1,72 +0,0 @@
<p align="center"><a href="https://1panel.cn"><img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>モダンでオープンソースの Linux サーバー運用管理パネル</b></p>
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel" alt="License: GPL v3"></a>
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a><br>
[<a href="README.md">中文</a>] | [<a href="README_EN.md">English</a>]
</p>
------------------------------
1Panel はモダンでオープンソースの Linux サーバー操作と管理パネルです:
- **素早いウェブサイト構築**: Wordpress および [Halo](https://github.com/halo-dev/halo/) と深く統合されており、ドメイン名のバインディング、SSL 証明書の設定など、ワンクリックで解決できます;
- **効率的なマネジメント**: アプリケーション管理、ホスト監視、ファイル管理、データベース管理、コンテナ管理など、web インターフェイスを通じて Linux サーバーを簡単に管理できます;
- **安全性と信頼性**: ファイアウォールとセキュリティ監査機能により、脆弱性の露出を最小限に抑えます;
- **ワンクリックバックアップ**: ワンクリックでのバックアップと復元をサポートし、バックアップデータはクラウドに保存され、失われることはありません。
## UI ディスプレイ
![UI Display](https://resource.fit2cloud.com/1panel/img/overview_en.png)
## クイックスタート
**オンラインでも**
- アドレス: <https://demo.1panel.cn/>
- ユーザネーム: demo
- パスワード: 1panel
**ワンクリックインストール**
ワンクリックで 1Panel をインストールするには、次のコマンドを実行します:
```sh
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
```
**学習教材**
- [オンラインドキュメント](https://1panel.cn/docs/)
- [ビデオ教材](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
## コミュニティ
ご質問やご提案がございましたら、GitHub Issue にご投稿いただくか、WeChat グループにご参加ください。
**WeChat グループ**
<img src="https://1panel.cn/img/wechat-group.jpg" width="156" height="156"/>
## セキュリティ情報
セキュリティ上の問題を発見された場合は、下記までご連絡ください:
- メール: support@fit2cloud.com
- 電話番号: 400-052-0755
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
## License
Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
<https://www.gnu.org/licenses/gpl-3.0.html>
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.
+26 -45
View File
@@ -1,6 +1,7 @@
package v1
import (
"errors"
"reflect"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
@@ -13,8 +14,8 @@ import (
)
// @Tags App
// @Summary Page app installed
// @Description 分页获取已安装应用列表
// @Summary List app installed
// @Description 获取已安装应用列表
// @Accept json
// @Param request body request.AppInstalledSearch true "request"
// @Success 200
@@ -46,41 +47,21 @@ func (b *BaseApi) SearchAppInstalled(c *gin.Context) {
}
}
// @Tags App
// @Summary List app installed
// @Description 获取已安装应用列表
// @Accept json
// @Success 200 array dto.AppInstallInfo
// @Security ApiKeyAuth
// @Router /apps/installed/list [get]
func (b *BaseApi) ListAppInstalled(c *gin.Context) {
list, err := appInstallService.GetInstallList()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags App
// @Summary Check app installed
// @Description 检查应用安装情况
// @Accept json
// @Param request body request.AppInstalledInfo true "request"
// @Param key path string true "request"
// @Success 200 {object} response.AppInstalledCheck
// @Security ApiKeyAuth
// @Router /apps/installed/check [post]
// @Router /apps/installed/check/:key [get]
func (b *BaseApi) CheckAppInstalled(c *gin.Context) {
var req request.AppInstalledInfo
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
key, ok := c.Params.Get("key")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
checkData, err := appInstallService.CheckExist(req)
checkData, err := appInstallService.CheckExist(key)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -92,17 +73,17 @@ func (b *BaseApi) CheckAppInstalled(c *gin.Context) {
// @Summary Search app port by key
// @Description 获取应用端口
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Param key path string true "request"
// @Success 200 {integer} port
// @Security ApiKeyAuth
// @Router /apps/installed/loadport [post]
// @Router /apps/installed/loadport/:key [get]
func (b *BaseApi) LoadPort(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
key, ok := c.Params.Get("key")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
return
}
port, err := appInstallService.LoadPort(req)
port, err := appInstallService.LoadPort(key)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -114,17 +95,17 @@ func (b *BaseApi) LoadPort(c *gin.Context) {
// @Summary Search app password by key
// @Description 获取应用连接信息
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Param key path string true "request"
// @Success 200 {string} response.DatabaseConn
// @Security ApiKeyAuth
// @Router /apps/installed/conninfo/:key [get]
func (b *BaseApi) LoadConnInfo(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
key, ok := c.Params.Get("key")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
return
}
conn, err := appInstallService.LoadConnInfo(req)
conn, err := appInstallService.LoadConnInfo(key)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -262,17 +243,17 @@ func (b *BaseApi) ChangeAppPort(c *gin.Context) {
// @Summary Search default config by key
// @Description 通过 key 获取应用默认配置
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Param key path string true "request"
// @Success 200 {string} content
// @Security ApiKeyAuth
// @Router /apps/installed/conf [post]
// @Router /apps/installed/conf/:key [get]
func (b *BaseApi) GetDefaultConfig(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
key := c.Param("key")
if key == "" {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
return
}
content, err := appInstallService.GetDefaultConfigByKey(req.Type, req.Name)
content, err := appInstallService.GetDefaultConfigByKey(key)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
+2 -16
View File
@@ -1,8 +1,6 @@
package v1
import (
"encoding/base64"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
@@ -22,7 +20,6 @@ type BaseApi struct{}
// @Param request body dto.Login true "request"
// @Success 200 {object} dto.UserLoginInfo
// @Router /auth/login [post]
// @Header 200 {string} EntranceCode "安全入口"
func (b *BaseApi) Login(c *gin.Context) {
var req dto.Login
if err := c.ShouldBindJSON(&req); err != nil {
@@ -35,13 +32,8 @@ func (b *BaseApi) Login(c *gin.Context) {
return
}
}
entranceItem := c.Request.Header.Get("EntranceCode")
var entrance []byte
if len(entranceItem) != 0 {
entrance, _ = base64.StdEncoding.DecodeString(entranceItem)
}
user, err := authService.Login(c, req, string(entrance))
user, err := authService.Login(c, req)
go saveLoginLogs(c, err)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@@ -57,7 +49,6 @@ func (b *BaseApi) Login(c *gin.Context) {
// @Param request body dto.MFALogin true "request"
// @Success 200 {object} dto.UserLoginInfo
// @Router /auth/mfalogin [post]
// @Header 200 {string} EntranceCode "安全入口"
func (b *BaseApi) MFALogin(c *gin.Context) {
var req dto.MFALogin
if err := c.ShouldBindJSON(&req); err != nil {
@@ -68,13 +59,8 @@ func (b *BaseApi) MFALogin(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
entranceItem := c.Request.Header.Get("EntranceCode")
var entrance []byte
if len(entranceItem) != 0 {
entrance, _ = base64.StdEncoding.DecodeString(entranceItem)
}
user, err := authService.MFALogin(c, req, string(entrance))
user, err := authService.MFALogin(c, req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
+3 -3
View File
@@ -335,7 +335,7 @@ func (b *BaseApi) Backup(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
case "mysql", "mariadb":
case "mysql":
if err := backupService.MysqlBackup(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -383,7 +383,7 @@ func (b *BaseApi) Recover(c *gin.Context) {
req.File = downloadPath
}
switch req.Type {
case "mysql", "mariadb":
case "mysql":
if err := backupService.MysqlRecover(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -428,7 +428,7 @@ func (b *BaseApi) RecoverByUpload(c *gin.Context) {
}
switch req.Type {
case "mysql", "mariadb":
case "mysql":
if err := backupService.MysqlRecoverByUpload(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
+16 -50
View File
@@ -143,7 +143,7 @@ func (b *BaseApi) ChangeMysqlAccess(c *gin.Context) {
// @Router /databases/variables/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"调整 mysql 数据库性能参数","formatEN":"adjust mysql database performance parameters"}
func (b *BaseApi) UpdateMysqlVariables(c *gin.Context) {
var req dto.MysqlVariablesUpdate
var req []dto.MysqlVariablesUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
@@ -232,21 +232,15 @@ func (b *BaseApi) ListDBName(c *gin.Context) {
// @Tags Database Mysql
// @Summary Load mysql database from remote
// @Description 从服务器获取
// @Accept json
// @Param request body dto.MysqlLoadDB true "request"
// @Security ApiKeyAuth
// @Router /databases/load [post]
// @Router /databases/load/:from [get]
func (b *BaseApi) LoadDBFromRemote(c *gin.Context) {
var req dto.MysqlLoadDB
if err := c.ShouldBindJSON(&req); err != nil {
from, err := helper.GetStrParamByKey(c, "from")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := mysqlService.LoadFromRemote(req); err != nil {
if err := mysqlService.LoadFromRemote(from); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
@@ -258,12 +252,12 @@ func (b *BaseApi) LoadDBFromRemote(c *gin.Context) {
// @Summary Check before delete mysql database
// @Description Mysql 数据库删除前检查
// @Accept json
// @Param request body dto.MysqlDBDeleteCheck true "request"
// @Param request body dto.OperateByID true "request"
// @Success 200 {array} string
// @Security ApiKeyAuth
// @Router /databases/del/check [post]
func (b *BaseApi) DeleteCheckMysql(c *gin.Context) {
var req dto.MysqlDBDeleteCheck
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
@@ -273,7 +267,7 @@ func (b *BaseApi) DeleteCheckMysql(c *gin.Context) {
return
}
apps, err := mysqlService.DeleteCheck(req)
apps, err := mysqlService.DeleteCheck(req.ID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -314,18 +308,11 @@ func (b *BaseApi) DeleteMysql(c *gin.Context) {
// @Tags Database Mysql
// @Summary Load mysql base info
// @Description 获取 mysql 基础信息
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200 {object} dto.DBBaseInfo
// @Security ApiKeyAuth
// @Router /databases/baseinfo [post]
// @Router /databases/baseinfo [get]
func (b *BaseApi) LoadBaseinfo(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := mysqlService.LoadBaseInfo(req)
data, err := mysqlService.LoadBaseInfo()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -359,18 +346,11 @@ func (b *BaseApi) LoadDatabaseFile(c *gin.Context) {
// @Tags Database Mysql
// @Summary Load mysql remote access
// @Description 获取 mysql 远程访问权限
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200 {boolean} isRemote
// @Security ApiKeyAuth
// @Router /databases/remote [post]
// @Router /databases/remote [get]
func (b *BaseApi) LoadRemoteAccess(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
isRemote, err := mysqlService.LoadRemoteAccess(req)
isRemote, err := mysqlService.LoadRemoteAccess()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -382,18 +362,11 @@ func (b *BaseApi) LoadRemoteAccess(c *gin.Context) {
// @Tags Database Mysql
// @Summary Load mysql status info
// @Description 获取 mysql 状态信息
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200 {object} dto.MysqlStatus
// @Security ApiKeyAuth
// @Router /databases/status [post]
// @Router /databases/status [get]
func (b *BaseApi) LoadStatus(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := mysqlService.LoadStatus(req)
data, err := mysqlService.LoadStatus()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -405,18 +378,11 @@ func (b *BaseApi) LoadStatus(c *gin.Context) {
// @Tags Database Mysql
// @Summary Load mysql variables info
// @Description 获取 mysql 性能参数信息
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200 {object} dto.MysqlVariables
// @Security ApiKeyAuth
// @Router /databases/variables [post]
// @Router /databases/variables [get]
func (b *BaseApi) LoadVariables(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := mysqlService.LoadVariables(req)
data, err := mysqlService.LoadVariables()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
+2 -2
View File
@@ -92,13 +92,13 @@ func (b *BaseApi) UpdateRedisConf(c *gin.Context) {
// @Summary Change redis password
// @Description 更新 redis 密码
// @Accept json
// @Param request body dto.ChangeRedisPass true "request"
// @Param request body dto.ChangeDBInfo true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/redis/password [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改 redis 数据库密码","formatEN":"change the password of the redis database"}
func (b *BaseApi) ChangeRedisPassword(c *gin.Context) {
var req dto.ChangeRedisPass
var req dto.ChangeDBInfo
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
+1 -1
View File
@@ -22,7 +22,7 @@ var (
dockerService = service.NewIDockerService()
mysqlService = service.NewIMysqlService()
databaseService = service.NewIDatabaseService()
remoteDBService = service.NewIRemoteDBService()
redisService = service.NewIRedisService()
cronjobService = service.NewICronjobService()
-29
View File
@@ -38,10 +38,6 @@ func (b *BaseApi) SearchFirewallRule(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
total, list, err := firewallService.SearchWithPage(req)
if err != nil {
@@ -160,31 +156,6 @@ func (b *BaseApi) BatchOperateRule(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags Firewall
// @Summary Update rule description
// @Description 更新防火墙描述
// @Accept json
// @Param request body dto.UpdateFirewallDescription true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/firewall/update/description [post]
func (b *BaseApi) UpdateFirewallDescription(c *gin.Context) {
var req dto.UpdateFirewallDescription
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := firewallService.UpdateDescription(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Firewall
// @Summary Create group
// @Description 更新端口防火墙规则
+15
View File
@@ -189,6 +189,21 @@ func (b *BaseApi) GetProcess(c *gin.Context) {
helper.SuccessWithData(c, configs)
}
// @Tags Host tool
// @Summary Load Supervisor process status
// @Description 获取 Supervisor 进程状态
// @Success 200 {array} response.ProcessStatus
// @Security ApiKeyAuth
// @Router /host/tool/supervisor/process/load [post]
func (b *BaseApi) LoadProcessStatus(c *gin.Context) {
datas, err := hostToolService.LoadProcessStatus()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, datas)
}
// @Tags Host tool
// @Summary Get Supervisor process config
// @Description 操作 Supervisor 进程文件
@@ -9,16 +9,16 @@ import (
)
// @Tags Database
// @Summary Create database
// @Summary Create remote database
// @Description 创建远程数据库
// @Accept json
// @Param request body dto.DatabaseCreate true "request"
// @Param request body dto.RemoteDBCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/db [post]
// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建远程数据库 [name][type]","formatEN":"create database [name][type]"}
func (b *BaseApi) CreateDatabase(c *gin.Context) {
var req dto.DatabaseCreate
// @Router /databases/remote [post]
// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建远程数据库 [name][type]","formatEN":"create remote database [name][type]"}
func (b *BaseApi) CreateRemoteDB(c *gin.Context) {
var req dto.RemoteDBCreate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
@@ -27,7 +27,7 @@ func (b *BaseApi) CreateDatabase(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := databaseService.Create(req); err != nil {
if err := remoteDBService.Create(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
@@ -35,16 +35,16 @@ func (b *BaseApi) CreateDatabase(c *gin.Context) {
}
// @Tags Database
// @Summary Check database
// @Summary Check remote database
// @Description 检测远程数据库连接性
// @Accept json
// @Param request body dto.DatabaseCreate true "request"
// @Param request body dto.RemoteDBCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/db/check [post]
// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"检测远程数据库 [name][type] 连接性","formatEN":"check if database [name][type] is connectable"}
func (b *BaseApi) CheckDatabase(c *gin.Context) {
var req dto.DatabaseCreate
// @Router /databases/remote/check [post]
// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"检测远程数据库 [name][type] 连接性","formatEN":"check if remote database [name][type] is connectable"}
func (b *BaseApi) CheckeRemoteDB(c *gin.Context) {
var req dto.RemoteDBCreate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
@@ -53,25 +53,25 @@ func (b *BaseApi) CheckDatabase(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
helper.SuccessWithData(c, databaseService.CheckDatabase(req))
helper.SuccessWithData(c, remoteDBService.CheckeRemoteDB(req))
}
// @Tags Database
// @Summary Page databases
// @Summary Page remote databases
// @Description 获取远程数据库列表分页
// @Accept json
// @Param request body dto.DatabaseSearch true "request"
// @Param request body dto.RemoteDBSearch true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /databases/db/search [post]
func (b *BaseApi) SearchDatabase(c *gin.Context) {
var req dto.DatabaseSearch
// @Router /databases/remote/search [post]
func (b *BaseApi) SearchRemoteDB(c *gin.Context) {
var req dto.RemoteDBSearch
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
total, list, err := databaseService.SearchWithPage(req)
total, list, err := remoteDBService.SearchWithPage(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -84,18 +84,18 @@ func (b *BaseApi) SearchDatabase(c *gin.Context) {
}
// @Tags Database
// @Summary List databases
// @Summary List remote databases
// @Description 获取远程数据库列表
// @Success 200 {array} dto.DatabaseOption
// @Success 200 {array} dto.RemoteDBOption
// @Security ApiKeyAuth
// @Router /databases/db/list/:type [get]
func (b *BaseApi) ListDatabase(c *gin.Context) {
// @Router /databases/remote/list/:type [get]
func (b *BaseApi) ListRemoteDB(c *gin.Context) {
dbType, err := helper.GetStrParamByKey(c, "type")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
list, err := databaseService.List(dbType)
list, err := remoteDBService.List(dbType)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -105,18 +105,18 @@ func (b *BaseApi) ListDatabase(c *gin.Context) {
}
// @Tags Database
// @Summary Get databases
// @Summary Get remote databases
// @Description 获取远程数据库
// @Success 200 {object} dto.DatabaseInfo
// @Success 200 {object} dto.RemoteDBInfo
// @Security ApiKeyAuth
// @Router /databases/db/:name [get]
func (b *BaseApi) GetDatabase(c *gin.Context) {
// @Router /databases/remote/:name [get]
func (b *BaseApi) GetRemoteDB(c *gin.Context) {
name, err := helper.GetStrParamByKey(c, "name")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := databaseService.Get(name)
data, err := remoteDBService.Get(name)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
@@ -126,15 +126,15 @@ func (b *BaseApi) GetDatabase(c *gin.Context) {
}
// @Tags Database
// @Summary Delete database
// @Summary Delete remote database
// @Description 删除远程数据库
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/db/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"databases","output_column":"name","output_value":"names"}],"formatZH":"删除远程数据库 [names]","formatEN":"delete database [names]"}
func (b *BaseApi) DeleteDatabase(c *gin.Context) {
// @Router /databases/remote/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"databases","output_column":"name","output_value":"names"}],"formatZH":"删除远程数据库 [names]","formatEN":"delete remote database [names]"}
func (b *BaseApi) DeleteRemoteDB(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
@@ -145,7 +145,7 @@ func (b *BaseApi) DeleteDatabase(c *gin.Context) {
return
}
if err := databaseService.Delete(req.ID); err != nil {
if err := remoteDBService.Delete(req.ID); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
@@ -153,16 +153,16 @@ func (b *BaseApi) DeleteDatabase(c *gin.Context) {
}
// @Tags Database
// @Summary Update database
// @Summary Update remote database
// @Description 更新远程数据库
// @Accept json
// @Param request body dto.DatabaseUpdate true "request"
// @Param request body dto.RemoteDBUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/db/update [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新远程数据库 [name]","formatEN":"update database [name]"}
func (b *BaseApi) UpdateDatabase(c *gin.Context) {
var req dto.DatabaseUpdate
// @Router /databases/remote/update [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新远程数据库 [name]","formatEN":"update remote database [name]"}
func (b *BaseApi) UpdateRemoteDB(c *gin.Context) {
var req dto.RemoteDBUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
@@ -172,7 +172,7 @@ func (b *BaseApi) UpdateDatabase(c *gin.Context) {
return
}
if err := databaseService.Update(req); err != nil {
if err := remoteDBService.Update(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
-26
View File
@@ -60,32 +60,6 @@ func (b *BaseApi) ImportSnapshot(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Load Snapshot status
// @Description 获取快照状态
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/status [post]
func (b *BaseApi) LoadSnapShotStatus(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
data, err := snapshotService.LoadSnapShotStatus(req.ID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags System Setting
// @Summary Update snapshot description
// @Description 更新快照描述信息
-22
View File
@@ -912,25 +912,3 @@ func (b *BaseApi) UpdateRedirectConfigFile(c *gin.Context) {
}
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Get website dir
// @Description 获取网站目录配置
// @Accept json
// @Param request body request.WebsiteCommonReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/dir [post]
func (b *BaseApi) GetDirConfig(c *gin.Context) {
var req request.WebsiteCommonReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
res, err := websiteService.LoadWebsiteDirConfig(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
-6
View File
@@ -133,9 +133,3 @@ var AppToolMap = map[string]string{
"mysql": "phpmyadmin",
"redis": "redis-commander",
}
type AppInstallInfo struct {
ID uint `json:"id"`
Key string `json:"key"`
Name string `json:"name"`
}
+9 -2
View File
@@ -21,18 +21,25 @@ type BackupInfo struct {
Vars string `json:"vars"`
}
type BackupSearch struct {
PageInfo
Type string `json:"type" validate:"required,oneof=website mysql"`
Name string `json:"name" validate:"required"`
DetailName string `json:"detailName"`
}
type BackupSearchFile struct {
Type string `json:"type" validate:"required"`
}
type CommonBackup struct {
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website"`
Type string `json:"type" validate:"required,oneof=app mysql redis website"`
Name string `json:"name"`
DetailName string `json:"detailName"`
}
type CommonRecover struct {
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO OneDrive"`
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website"`
Type string `json:"type" validate:"required,oneof=app mysql redis website"`
Name string `json:"name"`
DetailName string `json:"detailName"`
File string `json:"file"`
+1 -3
View File
@@ -24,8 +24,7 @@ type ContainerInfo struct {
State string `json:"state"`
RunTime string `json:"runTime"`
Network []string `json:"network"`
Ports []string `json:"ports"`
Ports []string `json:"ports"`
IsFromApp bool `json:"isFromApp"`
IsFromCompose bool `json:"isFromCompose"`
@@ -45,7 +44,6 @@ type ContainerOperate struct {
PublishAllPorts bool `json:"publishAllPorts"`
ExposedPorts []PortHelper `json:"exposedPorts"`
Cmd []string `json:"cmd"`
Entrypoint []string `json:"entrypoint"`
CPUShares int64 `json:"cpuShares"`
NanoCPUs float64 `json:"nanoCPUs"`
Memory float64 `json:"memory"`
-3
View File
@@ -14,7 +14,6 @@ type CronjobCreate struct {
Script string `json:"script"`
ContainerName string `json:"containerName"`
AppID string `json:"appID"`
Website string `json:"website"`
ExclusionRules string `json:"exclusionRules"`
DBName string `json:"dbName"`
@@ -37,7 +36,6 @@ type CronjobUpdate struct {
Script string `json:"script"`
ContainerName string `json:"containerName"`
AppID string `json:"appID"`
Website string `json:"website"`
ExclusionRules string `json:"exclusionRules"`
DBName string `json:"dbName"`
@@ -81,7 +79,6 @@ type CronjobInfo struct {
Script string `json:"script"`
ContainerName string `json:"containerName"`
AppID string `json:"appID"`
Website string `json:"website"`
ExclusionRules string `json:"exclusionRules"`
DBName string `json:"dbName"`
+21 -101
View File
@@ -4,10 +4,10 @@ import "time"
type MysqlDBSearch struct {
PageInfo
Info string `json:"info"`
Database string `json:"database" validate:"required"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
Info string `json:"info"`
From string `json:"from"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
}
type MysqlDBInfo struct {
@@ -25,17 +25,14 @@ type MysqlDBInfo struct {
}
type MysqlOption struct {
ID uint `json:"id"`
From string `json:"from"`
Type string `json:"type"`
Database string `json:"database"`
Name string `json:"name"`
ID uint `json:"id"`
Name string `json:"name"`
From string `json:"from"`
}
type MysqlDBCreate struct {
Name string `json:"name" validate:"required"`
From string `json:"from" validate:"required,oneof=local remote"`
Database string `json:"database" validate:"required"`
From string `json:"from" validate:"required"`
Format string `json:"format" validate:"required,oneof=utf8mb4 utf8 gbk big5"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
@@ -43,24 +40,10 @@ type MysqlDBCreate struct {
Description string `json:"description"`
}
type MysqlLoadDB struct {
From string `json:"from" validate:"required,oneof=local remote"`
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
Database string `json:"database" validate:"required"`
}
type MysqlDBDeleteCheck struct {
ID uint `json:"id" validate:"required"`
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
Database string `json:"database" validate:"required"`
}
type MysqlDBDelete struct {
ID uint `json:"id" validate:"required"`
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
Database string `json:"database" validate:"required"`
ForceDelete bool `json:"forceDelete"`
DeleteBackup bool `json:"deleteBackup"`
ID uint `json:"id" validate:"required"`
ForceDelete bool `json:"forceDelete"`
DeleteBackup bool `json:"deleteBackup"`
}
type MysqlStatus struct {
@@ -124,27 +107,18 @@ type MysqlVariables struct {
}
type MysqlVariablesUpdate struct {
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
Database string `json:"database" validate:"required"`
Variables []MysqlVariablesUpdateHelper `json:"variables"`
}
type MysqlVariablesUpdateHelper struct {
Param string `json:"param"`
Value interface{} `json:"value"`
}
type MysqlConfUpdateByFile struct {
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
Database string `json:"database" validate:"required"`
File string `json:"file"`
MysqlName string `json:"mysqlName" validate:"required"`
File string `json:"file"`
}
type ChangeDBInfo struct {
ID uint `json:"id"`
From string `json:"from" validate:"required,oneof=local remote"`
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
Database string `json:"database" validate:"required"`
Value string `json:"value" validate:"required"`
ID uint `json:"id"`
From string `json:"from"`
Value string `json:"value" validate:"required"`
}
type DBBaseInfo struct {
@@ -153,6 +127,11 @@ type DBBaseInfo struct {
Port int64 `json:"port"`
}
type SearchDBWithPage struct {
PageInfo
MysqlName string `json:"mysqlName" validate:"required"`
}
type BackupDB struct {
MysqlName string `json:"mysqlName" validate:"required"`
DBName string `json:"dbName" validate:"required"`
@@ -172,10 +151,6 @@ type UploadRecover struct {
}
// redis
type ChangeRedisPass struct {
Value string `json:"value" validate:"required"`
}
type RedisConfUpdate struct {
Timeout string `json:"timeout"`
Maxclients string `json:"maxclients"`
@@ -234,58 +209,3 @@ type RedisBackupRecover struct {
FileName string `json:"fileName"`
FileDir string `json:"fileDir"`
}
// database
type DatabaseSearch struct {
PageInfo
Info string `json:"info"`
Type string `json:"type"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
}
type DatabaseInfo struct {
ID uint `json:"id"`
CreatedAt time.Time `json:"createdAt"`
Name string `json:"name" validate:"max=256"`
From string `json:"from"`
Type string `json:"type"`
Version string `json:"version"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
Description string `json:"description"`
}
type DatabaseOption struct {
ID uint `json:"id"`
Type string `json:"type"`
From string `json:"from"`
Database string `json:"database"`
Version string `json:"version"`
Address string `json:"address"`
}
type DatabaseCreate struct {
Name string `json:"name" validate:"required,max=256"`
Type string `json:"type" validate:"required"`
From string `json:"from" validate:"required,oneof=local remote"`
Version string `json:"version" validate:"required"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
Description string `json:"description"`
}
type DatabaseUpdate struct {
ID uint `json:"id"`
Type string `json:"type" validate:"required"`
Version string `json:"version" validate:"required"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
Description string `json:"description"`
}
+2 -18
View File
@@ -9,10 +9,8 @@ type FirewallBaseInfo struct {
type RuleSearch struct {
PageInfo
Info string `json:"info"`
Status string `json:"status"`
Strategy string `json:"strategy"`
Type string `json:"type" validate:"required"`
Info string `json:"info"`
Type string `json:"type" validate:"required"`
}
type FirewallOperation struct {
@@ -25,26 +23,12 @@ type PortRuleOperate struct {
Port string `json:"port" validate:"required"`
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"`
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
Description string `json:"description"`
}
type UpdateFirewallDescription struct {
Type string `json:"type"`
Address string `json:"address"`
Port string `json:"port"`
Protocol string `json:"protocol"`
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
Description string `json:"description"`
}
type AddrRuleOperate struct {
Operation string `json:"operation" validate:"required,oneof=add remove"`
Address string `json:"address" validate:"required"`
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
Description string `json:"description"`
}
type PortRuleUpdate struct {
+52
View File
@@ -0,0 +1,52 @@
package dto
import "time"
type RemoteDBSearch struct {
PageInfo
Info string `json:"info"`
Type string `json:"type"`
OrderBy string `json:"orderBy"`
Order string `json:"order"`
}
type RemoteDBInfo struct {
ID uint `json:"id"`
CreatedAt time.Time `json:"createdAt"`
Name string `json:"name" validate:"max=256"`
From string `json:"from"`
Version string `json:"version"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
Description string `json:"description"`
}
type RemoteDBOption struct {
ID uint `json:"id"`
Name string `json:"name"`
Address string `json:"address"`
}
type RemoteDBCreate struct {
Name string `json:"name" validate:"required,max=256"`
Type string `json:"type" validate:"required,oneof=mysql"`
From string `json:"from" validate:"required,oneof=local remote"`
Version string `json:"version" validate:"required"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
Description string `json:"description"`
}
type RemoteDBUpdate struct {
ID uint `json:"id"`
Version string `json:"version" validate:"required"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
Description string `json:"description"`
}
-5
View File
@@ -41,11 +41,6 @@ type AppInstalledSearch struct {
Unused bool `json:"unused"`
}
type AppInstalledInfo struct {
Key string `json:"key" validate:"required"`
Name string `json:"name"`
}
type AppBackupSearch struct {
dto.PageInfo
AppInstallID uint `json:"appInstallID"`
-1
View File
@@ -29,5 +29,4 @@ type RuntimeUpdate struct {
Params map[string]interface{} `json:"params"`
Image string `json:"image"`
Version string `json:"version"`
Rebuild bool `json:"rebuild"`
}
+3 -9
View File
@@ -141,11 +141,9 @@ type WebsiteNginxUpdate struct {
}
type WebsiteLogReq struct {
ID uint `json:"id" validate:"required"`
Operate string `json:"operate" validate:"required"`
LogType string `json:"logType" validate:"required"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
ID uint `json:"id" validate:"required"`
Operate string `json:"operate" validate:"required"`
LogType string `json:"logType" validate:"required"`
}
type WebsiteDefaultUpdate struct {
@@ -213,7 +211,3 @@ type WebsiteWafFileUpdate struct {
Content string `json:"content" validate:"required"`
Type string `json:"type" validate:"required,oneof=cc ip_white ip_block url_white url_block cookie_block args_check post_check ua_check file_ext_block"`
}
type WebsiteCommonReq struct {
ID uint `json:"id" validate:"required"`
}
-2
View File
@@ -39,8 +39,6 @@ type AppInstalledCheck struct {
AppInstallID uint `json:"appInstallId"`
ContainerName string `json:"containerName"`
InstallPath string `json:"installPath"`
HttpPort int `json:"httpPort"`
HttpsPort int `json:"httpsPort"`
}
type AppDetailDTO struct {
-8
View File
@@ -41,7 +41,6 @@ type WebsiteHTTPS struct {
type WebsiteLog struct {
Enable bool `json:"enable"`
Content string `json:"content"`
End bool `json:"end"`
}
type PHPConfig struct {
@@ -53,10 +52,3 @@ type PHPConfig struct {
type NginxRewriteRes struct {
Content string `json:"content"`
}
type WebsiteDirConfig struct {
Dirs []string `json:"dirs"`
User string `json:"user"`
UserGroup string `json:"userGroup"`
Msg string `json:"msg"`
}
-14
View File
@@ -75,21 +75,7 @@ type PortUpdate struct {
ServerPort uint `json:"serverPort" validate:"required,number,max=65535,min=1"`
}
type SnapshotStatus struct {
Panel string `json:"panel"`
PanelInfo string `json:"panelInfo"`
DaemonJson string `json:"daemonJson"`
AppData string `json:"appData"`
PanelData string `json:"panelData"`
BackupData string `json:"backupData"`
Compress string `json:"compress"`
Size string `json:"size"`
Upload string `json:"upload"`
}
type SnapshotCreate struct {
ID uint `json:"id"`
From string `json:"from" validate:"required,oneof=OSS S3 SFTP MINIO COS KODO OneDrive"`
Description string `json:"description" validate:"max=256"`
}
@@ -6,5 +6,4 @@ type AppInstallResource struct {
LinkId uint `json:"linkId" gorm:"type:integer;not null;"`
ResourceId uint `json:"resourceId" gorm:"type:integer;"`
Key string `json:"key" gorm:"type:varchar(64);not null"`
From string `json:"from" gorm:"type:varchar(64);not null;default:local"`
}
-1
View File
@@ -18,7 +18,6 @@ type Cronjob struct {
ContainerName string `gorm:"type:varchar(64)" json:"containerName"`
Script string `gorm:"longtext" json:"script"`
Website string `gorm:"type:varchar(64)" json:"website"`
AppID string `gorm:"type:varchar(64)" json:"appID"`
DBName string `gorm:"type:varchar(64)" json:"dbName"`
URL string `gorm:"type:varchar(256)" json:"url"`
SourceDir string `gorm:"type:varchar(256)" json:"sourceDir"`
-15
View File
@@ -1,15 +0,0 @@
package model
type Database struct {
BaseModel
AppInstallID uint `json:"appInstallID" gorm:"type:decimal"`
Name string `json:"name" gorm:"type:varchar(64);not null;unique"`
Type string `json:"type" gorm:"type:varchar(64);not null"`
Version string `json:"version" gorm:"type:varchar(64);not null"`
From string `json:"from" gorm:"type:varchar(64);not null"`
Address string `json:"address" gorm:"type:varchar(64);not null"`
Port uint `json:"port" gorm:"type:decimal;not null"`
Username string `json:"username" gorm:"type:varchar(64)"`
Password string `json:"password" gorm:"type:varchar(64)"`
Description string `json:"description" gorm:"type:varchar(256);"`
}
-12
View File
@@ -1,12 +0,0 @@
package model
type Firewall struct {
BaseModel
Type string `gorm:"type:varchar(64);not null" json:"type"`
Port string `gorm:"type:varchar(64);not null" json:"port"`
Protocol string `gorm:"type:varchar(64);not null" json:"protocol"`
Address string `gorm:"type:varchar(64);not null" json:"address"`
Strategy string `gorm:"type:varchar(64);not null" json:"strategy"`
Description string `gorm:"type:varchar(64);not null" json:"description"`
}
+14
View File
@@ -0,0 +1,14 @@
package model
type RemoteDB struct {
BaseModel
Name string `json:"name" gorm:"type:varchar(64);not null"`
Type string `json:"type" gorm:"type:varchar(64);not null"`
Version string `json:"version" gorm:"type:varchar(64);not null"`
From string `json:"from" gorm:"type:varchar(64);not null"`
Address string `json:"address" gorm:"type:varchar(64);not null"`
Port uint `json:"port" gorm:"type:decimal;not null"`
Username string `json:"username" gorm:"type:varchar(64)"`
Password string `json:"password" gorm:"type:varchar(64)"`
Description string `json:"description" gorm:"type:varchar(256);"`
}
-15
View File
@@ -17,18 +17,3 @@ type Snapshot struct {
RollbackMessage string `json:"rollbackMessage" gorm:"type:varchar(256)"`
LastRollbackedAt string `json:"lastRollbackedAt" gorm:"type:varchar(64)"`
}
type SnapshotStatus struct {
BaseModel
SnapID uint `gorm:"type:decimal" json:"snapID"`
Panel string `json:"panel" gorm:"type:varchar(64);default:Running"`
PanelInfo string `json:"panelInfo" gorm:"type:varchar(64);default:Running"`
DaemonJson string `json:"daemonJson" gorm:"type:varchar(64);default:Running"`
AppData string `json:"appData" gorm:"type:varchar(64);default:Running"`
PanelData string `json:"panelData" gorm:"type:varchar(64);default:Running"`
BackupData string `json:"backupData" gorm:"type:varchar(64);default:Running"`
Compress string `json:"compress" gorm:"type:varchar(64);default:Waiting"`
Size string `json:"size" gorm:"type:varchar(64)"`
Upload string `json:"upload" gorm:"type:varchar(64);default:Waiting"`
}
+1 -1
View File
@@ -66,7 +66,7 @@ func (a AppRepo) Page(page, size int, opts ...DBOption) (int64, []model.App, err
db := getDb(opts...).Model(&model.App{})
count := int64(0)
db = db.Count(&count)
err := db.Limit(size).Offset(size * (page - 1)).Preload("AppTags").Find(&apps).Error
err := db.Debug().Limit(size).Offset(size * (page - 1)).Preload("AppTags").Find(&apps).Error
return count, apps, err
}
+1 -13
View File
@@ -3,7 +3,6 @@ package repo
import (
"context"
"encoding/json"
"gorm.io/gorm/clause"
"github.com/1Panel-dev/1Panel/backend/app/model"
@@ -161,7 +160,6 @@ type RootInfo struct {
Name string `json:"name"`
Port int64 `json:"port"`
HttpsPort int64 `json:"httpsPort"`
UserName string `json:"userName"`
Password string `json:"password"`
UserPassword string `json:"userPassword"`
ContainerName string `json:"containerName"`
@@ -195,7 +193,7 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
return nil, err
}
switch app.Key {
case "mysql", "mariadb":
case "mysql":
password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string)
if ok {
info.Password = password
@@ -205,15 +203,6 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
if ok {
info.Password = password
}
case "mongodb", "postgresql":
user, ok := envMap["PANEL_DB_ROOT_USER"].(string)
if ok {
info.UserName = user
}
password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string)
if ok {
info.Password = password
}
}
userPassword, ok := envMap["PANEL_DB_USER_PASSWORD"].(string)
@@ -229,6 +218,5 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
info.Env = appInstall.Env
info.Param = appInstall.Param
info.Version = appInstall.Version
info.Key = app.Key
return &info, nil
}
-143
View File
@@ -1,143 +0,0 @@
package repo
import (
"context"
"fmt"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"gorm.io/gorm"
)
type DatabaseRepo struct{}
type IDatabaseRepo interface {
GetList(opts ...DBOption) ([]model.Database, error)
Page(limit, offset int, opts ...DBOption) (int64, []model.Database, error)
Create(ctx context.Context, database *model.Database) error
Update(id uint, vars map[string]interface{}) error
Delete(ctx context.Context, opts ...DBOption) error
Get(opts ...DBOption) (model.Database, error)
WithByFrom(from string) DBOption
WithoutByFrom(from string) DBOption
WithAppInstallID(appInstallID uint) DBOption
WithTypeList(dbType string) DBOption
}
func NewIDatabaseRepo() IDatabaseRepo {
return &DatabaseRepo{}
}
func (d *DatabaseRepo) Get(opts ...DBOption) (model.Database, error) {
var database model.Database
db := global.DB
for _, opt := range opts {
db = opt(db)
}
if err := db.First(&database).Error; err != nil {
return database, err
}
pass, err := encrypt.StringDecrypt(database.Password)
if err != nil {
global.LOG.Errorf("decrypt database %s password failed, err: %v", database.Name, err)
}
database.Password = pass
return database, nil
}
func (d *DatabaseRepo) Page(page, size int, opts ...DBOption) (int64, []model.Database, error) {
var databases []model.Database
db := global.DB.Model(&model.Database{})
for _, opt := range opts {
db = opt(db)
}
count := int64(0)
db = db.Count(&count)
if err := db.Limit(size).Offset(size * (page - 1)).Find(&databases).Error; err != nil {
return count, databases, err
}
for i := 0; i < len(databases); i++ {
pass, err := encrypt.StringDecrypt(databases[i].Password)
if err != nil {
global.LOG.Errorf("decrypt database db %s password failed, err: %v", databases[i].Name, err)
}
databases[i].Password = pass
}
return count, databases, nil
}
func (d *DatabaseRepo) GetList(opts ...DBOption) ([]model.Database, error) {
var databases []model.Database
db := global.DB.Model(&model.Database{})
for _, opt := range opts {
db = opt(db)
}
if err := db.Find(&databases).Error; err != nil {
return databases, err
}
for i := 0; i < len(databases); i++ {
pass, err := encrypt.StringDecrypt(databases[i].Password)
if err != nil {
global.LOG.Errorf("decrypt database db %s password failed, err: %v", databases[i].Name, err)
}
databases[i].Password = pass
}
return databases, nil
}
func (d *DatabaseRepo) WithByFrom(from string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("`from` = ?", from)
}
}
func (d *DatabaseRepo) WithoutByFrom(from string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("`from` != ?", from)
}
}
func (d *DatabaseRepo) WithTypeList(dbType string) DBOption {
return func(g *gorm.DB) *gorm.DB {
if !strings.Contains(dbType, ",") {
return g.Where("`type` = ?", dbType)
}
types := strings.Split(dbType, ",")
var (
rules []string
values []interface{}
)
for _, ty := range types {
if len(ty) != 0 {
rules = append(rules, "`type` = ?")
values = append(values, ty)
}
}
return g.Where(strings.Join(rules, " OR "), values...)
}
}
func (d *DatabaseRepo) WithAppInstallID(appInstallID uint) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("app_install_id = ?", appInstallID)
}
}
func (d *DatabaseRepo) Create(ctx context.Context, database *model.Database) error {
pass, err := encrypt.StringEncrypt(database.Password)
if err != nil {
return fmt.Errorf("decrypt database db %s password failed, err: %v", database.Name, err)
}
database.Password = pass
return getTx(ctx).Create(database).Error
}
func (d *DatabaseRepo) Update(id uint, vars map[string]interface{}) error {
return global.DB.Model(&model.Database{}).Where("id = ?", id).Updates(vars).Error
}
func (d *DatabaseRepo) Delete(ctx context.Context, opts ...DBOption) error {
return getTx(ctx, opts...).Delete(&model.Database{}).Error
}
+15 -40
View File
@@ -2,11 +2,9 @@ package repo
import (
"context"
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"gorm.io/gorm"
)
@@ -21,6 +19,7 @@ type IMysqlRepo interface {
Create(ctx context.Context, mysql *model.DatabaseMysql) error
Delete(ctx context.Context, opts ...DBOption) error
Update(id uint, vars map[string]interface{}) error
UpdateDatabaseInfo(id uint, vars map[string]interface{}) error
DeleteLocal(ctx context.Context) error
}
@@ -34,64 +33,33 @@ func (u *MysqlRepo) Get(opts ...DBOption) (model.DatabaseMysql, error) {
for _, opt := range opts {
db = opt(db)
}
if err := db.First(&mysql).Error; err != nil {
return mysql, err
}
pass, err := encrypt.StringDecrypt(mysql.Password)
if err != nil {
global.LOG.Errorf("decrypt database db %s password failed, err: %v", mysql.Name, err)
}
mysql.Password = pass
err := db.First(&mysql).Error
return mysql, err
}
func (u *MysqlRepo) List(opts ...DBOption) ([]model.DatabaseMysql, error) {
var mysqls []model.DatabaseMysql
var users []model.DatabaseMysql
db := global.DB.Model(&model.DatabaseMysql{})
for _, opt := range opts {
db = opt(db)
}
if err := db.Find(&mysqls).Error; err != nil {
return mysqls, err
}
for i := 0; i < len(mysqls); i++ {
pass, err := encrypt.StringDecrypt(mysqls[i].Password)
if err != nil {
global.LOG.Errorf("decrypt database db %s password failed, err: %v", mysqls[i].Name, err)
}
mysqls[i].Password = pass
}
return mysqls, nil
err := db.Find(&users).Error
return users, err
}
func (u *MysqlRepo) Page(page, size int, opts ...DBOption) (int64, []model.DatabaseMysql, error) {
var mysqls []model.DatabaseMysql
var users []model.DatabaseMysql
db := global.DB.Model(&model.DatabaseMysql{})
for _, opt := range opts {
db = opt(db)
}
count := int64(0)
db = db.Count(&count)
if err := db.Limit(size).Offset(size * (page - 1)).Find(&mysqls).Error; err != nil {
return count, mysqls, err
}
for i := 0; i < len(mysqls); i++ {
pass, err := encrypt.StringDecrypt(mysqls[i].Password)
if err != nil {
global.LOG.Errorf("decrypt database db %s password failed, err: %v", mysqls[i].Name, err)
}
mysqls[i].Password = pass
}
return count, mysqls, nil
err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error
return count, users, err
}
func (u *MysqlRepo) Create(ctx context.Context, mysql *model.DatabaseMysql) error {
pass, err := encrypt.StringEncrypt(mysql.Password)
if err != nil {
return fmt.Errorf("decrypt database db %s password failed, err: %v", mysql.Name, err)
}
mysql.Password = pass
return getTx(ctx).Create(mysql).Error
}
@@ -107,6 +75,13 @@ func (u *MysqlRepo) Update(id uint, vars map[string]interface{}) error {
return global.DB.Model(&model.DatabaseMysql{}).Where("id = ?", id).Updates(vars).Error
}
func (u *MysqlRepo) UpdateDatabaseInfo(id uint, vars map[string]interface{}) error {
if err := global.DB.Model(&model.AppInstall{}).Where("id = ?", id).Updates(vars).Error; err != nil {
return err
}
return nil
}
func (u *MysqlRepo) WithByMysqlName(mysqlName string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("mysql_name = ?", mysqlName)
-51
View File
@@ -19,12 +19,6 @@ type IHostRepo interface {
Create(host *model.Host) error
Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error
GetFirewallRecord(opts ...DBOption) (model.Firewall, error)
ListFirewallRecord() ([]model.Firewall, error)
SaveFirewallRecord(firewall *model.Firewall) error
DeleteFirewallRecordByID(id uint) error
DeleteFirewallRecord(fType, port, protocol, address, strategy string) error
}
func NewIHostRepo() IHostRepo {
@@ -112,48 +106,3 @@ func (h *HostRepo) Delete(opts ...DBOption) error {
}
return db.Delete(&model.Host{}).Error
}
func (h *HostRepo) GetFirewallRecord(opts ...DBOption) (model.Firewall, error) {
var firewall model.Firewall
db := global.DB
for _, opt := range opts {
db = opt(db)
}
err := db.First(&firewall).Error
return firewall, err
}
func (h *HostRepo) ListFirewallRecord() ([]model.Firewall, error) {
var datas []model.Firewall
if err := global.DB.Find(&datas).Error; err != nil {
return datas, nil
}
return datas, nil
}
func (h *HostRepo) SaveFirewallRecord(firewall *model.Firewall) error {
if firewall.ID != 0 {
return global.DB.Save(firewall).Error
}
var data model.Firewall
if firewall.Type == "port" {
_ = global.DB.Where("type = ? AND port = ? AND protocol = ? AND address = ? AND strategy = ?", "port", firewall.Port, firewall.Protocol, firewall.Address, firewall.Strategy).First(&data)
if data.ID != 0 {
firewall.ID = data.ID
}
} else {
_ = global.DB.Where("type = ? AND address = ? AND strategy = ?", "address", firewall.Address, firewall.Strategy).First(&data)
if data.ID != 0 {
firewall.ID = data.ID
}
}
return global.DB.Save(firewall).Error
}
func (h *HostRepo) DeleteFirewallRecordByID(id uint) error {
return global.DB.Where("id = ?", id).Delete(&model.Firewall{}).Error
}
func (h *HostRepo) DeleteFirewallRecord(fType, port, protocol, address, strategy string) error {
return global.DB.Where("type = ? AND port = ? AND protocol = ? AND address = ? AND strategy = ?", fType, port, protocol, address, strategy).Delete(&model.Firewall{}).Error
}
+84
View File
@@ -0,0 +1,84 @@
package repo
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"gorm.io/gorm"
)
type RemoteDBRepo struct{}
type IRemoteDBRepo interface {
GetList(opts ...DBOption) ([]model.RemoteDB, error)
Page(limit, offset int, opts ...DBOption) (int64, []model.RemoteDB, error)
Create(database *model.RemoteDB) error
Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error
Get(opts ...DBOption) (model.RemoteDB, error)
WithByFrom(from string) DBOption
WithoutByFrom(from string) DBOption
}
func NewIRemoteDBRepo() IRemoteDBRepo {
return &RemoteDBRepo{}
}
func (u *RemoteDBRepo) Get(opts ...DBOption) (model.RemoteDB, error) {
var database model.RemoteDB
db := global.DB
for _, opt := range opts {
db = opt(db)
}
err := db.First(&database).Error
return database, err
}
func (u *RemoteDBRepo) Page(page, size int, opts ...DBOption) (int64, []model.RemoteDB, error) {
var users []model.RemoteDB
db := global.DB.Model(&model.RemoteDB{})
for _, opt := range opts {
db = opt(db)
}
count := int64(0)
db = db.Count(&count)
err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error
return count, users, err
}
func (u *RemoteDBRepo) GetList(opts ...DBOption) ([]model.RemoteDB, error) {
var databases []model.RemoteDB
db := global.DB.Model(&model.RemoteDB{})
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&databases).Error
return databases, err
}
func (c *RemoteDBRepo) WithByFrom(from string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("`from` == ?", from)
}
}
func (c *RemoteDBRepo) WithoutByFrom(from string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("`from` != ?", from)
}
}
func (u *RemoteDBRepo) Create(database *model.RemoteDB) error {
return global.DB.Create(database).Error
}
func (u *RemoteDBRepo) Update(id uint, vars map[string]interface{}) error {
return global.DB.Model(&model.RemoteDB{}).Where("id = ?", id).Updates(vars).Error
}
func (u *RemoteDBRepo) Delete(opts ...DBOption) error {
db := global.DB
for _, opt := range opts {
db = opt(db)
}
return db.Delete(&model.RemoteDB{}).Error
}
-13
View File
@@ -2,9 +2,7 @@ package repo
import (
"context"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"gorm.io/gorm"
)
@@ -22,7 +20,6 @@ type IRuntimeRepo interface {
Save(runtime *model.Runtime) error
DeleteBy(opts ...DBOption) error
GetFirst(opts ...DBOption) (*model.Runtime, error)
List(opts ...DBOption) ([]model.Runtime, error)
}
func NewIRunTimeRepo() IRuntimeRepo {
@@ -68,16 +65,6 @@ func (r *RuntimeRepo) Page(page, size int, opts ...DBOption) (int64, []model.Run
return count, runtimes, err
}
func (r *RuntimeRepo) List(opts ...DBOption) ([]model.Runtime, error) {
var runtimes []model.Runtime
db := global.DB.Model(&model.Runtime{})
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&runtimes).Error
return runtimes, err
}
func (r *RuntimeRepo) Create(ctx context.Context, runtime *model.Runtime) error {
db := getTx(ctx).Model(&model.Runtime{})
return db.Create(&runtime).Error
-36
View File
@@ -12,12 +12,6 @@ type ISnapshotRepo interface {
Update(id uint, vars map[string]interface{}) error
Page(limit, offset int, opts ...DBOption) (int64, []model.Snapshot, error)
Delete(opts ...DBOption) error
GetStatus(snapID uint) (model.SnapshotStatus, error)
GetStatusList(opts ...DBOption) ([]model.SnapshotStatus, error)
CreateStatus(snap *model.SnapshotStatus) error
DeleteStatus(snapID uint) error
UpdateStatus(id uint, vars map[string]interface{}) error
}
func NewISnapshotRepo() ISnapshotRepo {
@@ -73,33 +67,3 @@ func (u *SnapshotRepo) Delete(opts ...DBOption) error {
}
return db.Delete(&model.Snapshot{}).Error
}
func (u *SnapshotRepo) GetStatus(snapID uint) (model.SnapshotStatus, error) {
var data model.SnapshotStatus
if err := global.DB.Where("snap_id = ?", snapID).First(&data).Error; err != nil {
return data, err
}
return data, nil
}
func (u *SnapshotRepo) GetStatusList(opts ...DBOption) ([]model.SnapshotStatus, error) {
var status []model.SnapshotStatus
db := global.DB.Model(&model.SnapshotStatus{})
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&status).Error
return status, err
}
func (u *SnapshotRepo) CreateStatus(snap *model.SnapshotStatus) error {
return global.DB.Create(snap).Error
}
func (u *SnapshotRepo) DeleteStatus(snapID uint) error {
return global.DB.Where("snap_id = ?", snapID).Delete(&model.SnapshotStatus{}).Error
}
func (u *SnapshotRepo) UpdateStatus(id uint, vars map[string]interface{}) error {
return global.DB.Model(&model.SnapshotStatus{}).Where("id = ?", id).Updates(vars).Error
}
-5
View File
@@ -26,7 +26,6 @@ type IWebsiteRepo interface {
SaveWithoutCtx(app *model.Website) error
DeleteBy(ctx context.Context, opts ...DBOption) error
Create(ctx context.Context, app *model.Website) error
DeleteAll(ctx context.Context) error
}
func NewIWebsiteRepo() IWebsiteRepo {
@@ -132,7 +131,3 @@ func (w *WebsiteRepo) SaveWithoutCtx(website *model.Website) error {
func (w *WebsiteRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
return getTx(ctx, opts...).Delete(&model.Website{}).Error
}
func (w *WebsiteRepo) DeleteAll(ctx context.Context) error {
return getTx(ctx).Where("1 = 1 ").Delete(&model.Website{}).Error
}
-5
View File
@@ -21,7 +21,6 @@ type IWebsiteDomainRepo interface {
Create(ctx context.Context, app *model.WebsiteDomain) error
Save(ctx context.Context, app *model.WebsiteDomain) error
DeleteBy(ctx context.Context, opts ...DBOption) error
DeleteAll(ctx context.Context) error
}
func NewIWebsiteDomainRepo() IWebsiteDomainRepo {
@@ -86,7 +85,3 @@ func (w WebsiteDomainRepo) Save(ctx context.Context, app *model.WebsiteDomain) e
func (w WebsiteDomainRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
return getTx(ctx, opts...).Delete(&model.WebsiteDomain{}).Error
}
func (w WebsiteDomainRepo) DeleteAll(ctx context.Context) error {
return getTx(ctx).Where("1 = 1 ").Delete(&model.WebsiteDomain{}).Error
}
+17 -40
View File
@@ -23,7 +23,6 @@ import (
"net/http"
"os"
"path"
"reflect"
"strconv"
"strings"
)
@@ -275,20 +274,6 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
appDetail model.AppDetail
app model.App
)
appDetail, err = appDetailRepo.GetFirst(commonRepo.WithByID(req.AppDetailId))
if err != nil {
return
}
app, err = appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
if err != nil {
return
}
if DatabaseKeys[app.Key] > 0 {
if existDatabases, _ := databaseRepo.GetList(commonRepo.WithByName(req.Name)); len(existDatabases) > 0 {
err = buserr.New(constant.ErrRemoteExist)
return
}
}
for key := range req.Params {
if !strings.Contains(key, "PANEL_APP_PORT") {
continue
@@ -306,6 +291,14 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
}
}
appDetail, err = appDetailRepo.GetFirst(commonRepo.WithByID(req.AppDetailId))
if err != nil {
return
}
app, err = appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
if err != nil {
return
}
if err = checkRequiredAndLimit(app); err != nil {
return
}
@@ -359,20 +352,13 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
appInstall.ContainerName = containerName
index := 0
serviceName := ""
for k := range servicesMap {
serviceName = k
appInstall.ServiceName = k
if index > 0 {
continue
}
index++
}
if app.Limit == 0 && appInstall.Name != serviceName {
servicesMap[appInstall.Name] = servicesMap[serviceName]
delete(servicesMap, serviceName)
serviceName = appInstall.Name
}
appInstall.ServiceName = serviceName
if err = addDockerComposeCommonParam(composeMap, appInstall.ServiceName, req.AppContainerConfig, req.Params); err != nil {
return
@@ -396,14 +382,6 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
}
}
}()
if hostName, ok := req.Params["PANEL_DB_HOST"]; ok {
database, _ := databaseRepo.Get(commonRepo.WithByName(hostName.(string)))
if !reflect.DeepEqual(database, model.Database{}) {
req.Params["PANEL_DB_HOST"] = database.Address
req.Params["PANEL_DB_PORT"] = database.Port
req.Params["PANEL_DB_HOST_NAME"] = hostName
}
}
paramByte, err = json.Marshal(req.Params)
if err != nil {
return
@@ -416,17 +394,15 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
return
}
go func() {
defer func() {
if err != nil {
if err = copyData(app, appDetail, appInstall, req); err != nil {
if appInstall.Status == constant.Installing {
appInstall.Status = constant.Error
appInstall.Message = err.Error()
_ = appInstallRepo.Save(context.Background(), appInstall)
}
}()
if err = copyData(app, appDetail, appInstall, req); err != nil {
_ = appInstallRepo.Save(context.Background(), appInstall)
return
}
if err = runScript(appInstall, "init"); err != nil {
if err = upAppPre(app, appInstall); err != nil {
return
}
upApp(appInstall)
@@ -804,8 +780,9 @@ func (a AppService) SyncAppListFromRemote() (err error) {
for _, v := range versions {
version := v.Name
detail := detailsMap[version]
versionUrl := fmt.Sprintf("%s/%s/%s", baseRemoteUrl, app.Key, version)
dockerComposeUrl := fmt.Sprintf("%s/%s", versionUrl, "docker-compose.yml")
remoteVersionUrl := fmt.Sprintf("%s/%s/%s", baseRemoteUrl, app.Key, version)
dockerComposeUrl := fmt.Sprintf("%s/%s", remoteVersionUrl, "docker-compose.yml")
composeRes, err := http.Get(dockerComposeUrl)
if err != nil {
return err
@@ -818,7 +795,7 @@ func (a AppService) SyncAppListFromRemote() (err error) {
paramByte, _ := json.Marshal(v.AppForm)
detail.Params = string(paramByte)
detail.DownloadUrl = fmt.Sprintf("%s/%s", versionUrl, app.Key+"-"+version+".tar.gz")
detail.DownloadUrl = fmt.Sprintf("%s/%s", remoteVersionUrl, version+".tar.gz")
detail.DownloadCallBackUrl = v.DownloadCallBackUrl
detail.Update = true
detail.LastModified = v.LastModified
+45 -94
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/i18n"
"math"
"os"
"path"
@@ -11,8 +12,6 @@ import (
"strconv"
"strings"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"gopkg.in/yaml.v3"
@@ -41,9 +40,9 @@ type AppInstallService struct {
type IAppInstallService interface {
Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error)
CheckExist(req request.AppInstalledInfo) (*response.AppInstalledCheck, error)
LoadPort(req dto.OperationWithNameAndType) (int64, error)
LoadConnInfo(req dto.OperationWithNameAndType) (response.DatabaseConn, error)
CheckExist(key string) (*response.AppInstalledCheck, error)
LoadPort(key string) (int64, error)
LoadConnInfo(key string) (response.DatabaseConn, error)
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error)
Operate(req request.AppInstalledOperate) error
Update(req request.AppInstalledUpdate) error
@@ -53,28 +52,14 @@ type IAppInstallService interface {
GetUpdateVersions(installId uint) ([]dto.AppVersion, error)
GetParams(id uint) (*response.AppConfig, error)
ChangeAppPort(req request.PortUpdate) error
GetDefaultConfigByKey(key, name string) (string, error)
GetDefaultConfigByKey(key string) (string, error)
DeleteCheck(installId uint) ([]dto.AppResource, error)
GetInstallList() ([]dto.AppInstallInfo, error)
}
func NewIAppInstalledService() IAppInstallService {
return &AppInstallService{}
}
func (a *AppInstallService) GetInstallList() ([]dto.AppInstallInfo, error) {
var datas []dto.AppInstallInfo
appInstalls, err := appInstallRepo.ListBy()
if err != nil {
return nil, err
}
for _, install := range appInstalls {
datas = append(datas, dto.AppInstallInfo{ID: install.ID, Key: install.App.Key, Name: install.Name})
}
return datas, nil
}
func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error) {
var (
opts []repo.DBOption
@@ -130,30 +115,23 @@ func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []respo
return total, installDTOs, nil
}
func (a *AppInstallService) CheckExist(req request.AppInstalledInfo) (*response.AppInstalledCheck, error) {
func (a *AppInstallService) CheckExist(key string) (*response.AppInstalledCheck, error) {
res := &response.AppInstalledCheck{
IsExist: false,
}
app, err := appRepo.GetFirst(appRepo.WithKey(req.Key))
app, err := appRepo.GetFirst(appRepo.WithKey(key))
if err != nil {
return res, nil
}
res.App = app.Name
var appInstall model.AppInstall
if len(req.Name) == 0 {
appInstall, _ = appInstallRepo.GetFirst(appInstallRepo.WithAppId(app.ID))
} else {
appInstall, _ = appInstallRepo.GetFirst(appInstallRepo.WithAppId(app.ID), commonRepo.WithByName(req.Name))
}
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithAppId(app.ID))
if reflect.DeepEqual(appInstall, model.AppInstall{}) {
return res, nil
}
if err = syncByID(appInstall.ID); err != nil {
if err := syncById(appInstall.ID); err != nil {
return nil, err
}
appInstall, _ = appInstallRepo.GetFirst(commonRepo.WithByID(appInstall.ID))
res.ContainerName = appInstall.ContainerName
res.Name = appInstall.Name
@@ -162,24 +140,22 @@ func (a *AppInstallService) CheckExist(req request.AppInstalledInfo) (*response.
res.Status = appInstall.Status
res.AppInstallID = appInstall.ID
res.IsExist = true
res.InstallPath = path.Join(constant.AppInstallDir, appInstall.App.Key, appInstall.Name)
res.HttpPort = appInstall.HttpPort
res.HttpsPort = appInstall.HttpsPort
res.InstallPath = path.Join(constant.AppInstallDir, app.Key, appInstall.Name)
return res, nil
}
func (a *AppInstallService) LoadPort(req dto.OperationWithNameAndType) (int64, error) {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
func (a *AppInstallService) LoadPort(key string) (int64, error) {
app, err := appInstallRepo.LoadBaseInfo(key, "")
if err != nil {
return int64(0), nil
}
return app.Port, nil
}
func (a *AppInstallService) LoadConnInfo(req dto.OperationWithNameAndType) (response.DatabaseConn, error) {
func (a *AppInstallService) LoadConnInfo(key string) (response.DatabaseConn, error) {
var data response.DatabaseConn
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
app, err := appInstallRepo.LoadBaseInfo(key, "")
if err != nil {
return data, nil
}
@@ -239,26 +215,26 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
if err != nil {
return handleErr(install, err, out)
}
return syncByID(install.ID)
return syncById(install.ID)
case constant.Stop:
out, err := compose.Stop(dockerComposePath)
if err != nil {
return handleErr(install, err, out)
}
return syncByID(install.ID)
return syncById(install.ID)
case constant.Restart:
out, err := compose.Restart(dockerComposePath)
if err != nil {
return handleErr(install, err, out)
}
return syncByID(install.ID)
return syncById(install.ID)
case constant.Delete:
if err := deleteAppInstall(install, req.DeleteBackup, req.ForceDelete, req.DeleteDB); err != nil && !req.ForceDelete {
return err
}
return nil
case constant.Sync:
return syncByID(install.ID)
return syncById(install.ID)
case constant.Upgrade:
return upgradeInstall(install.ID, req.DetailId, req.Backup)
default:
@@ -417,7 +393,7 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
continue
}
if !systemInit {
if err := syncByID(i.ID); err != nil {
if err := syncById(i.ID); err != nil {
global.LOG.Errorf("sync install app[%s] error,mgs: %s", i.Name, err.Error())
}
}
@@ -426,50 +402,25 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
}
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
app, err := appRepo.GetFirst(appRepo.WithKey(key))
if err != nil {
return nil, err
}
installs, err := appInstallRepo.ListBy(appInstallRepo.WithAppId(app.ID), appInstallRepo.WithStatus(constant.Running))
if err != nil {
return nil, err
}
var res []response.AppService
if DatabaseKeys[key] > 0 {
dbs, _ := databaseRepo.GetList(databaseRepo.WithByFrom("local"), commonRepo.WithByType(key))
if len(dbs) == 0 {
return res, nil
}
for _, db := range dbs {
service := response.AppService{
Label: db.Name,
Value: db.Name,
}
if db.AppInstallID > 0 {
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(db.AppInstallID))
if err != nil {
return nil, err
}
paramMap := make(map[string]string)
if install.Param != "" {
_ = json.Unmarshal([]byte(install.Param), &paramMap)
}
service.Config = paramMap
}
res = append(res, service)
}
} else {
app, err := appRepo.GetFirst(appRepo.WithKey(key))
if err != nil {
return nil, err
}
installs, err := appInstallRepo.ListBy(appInstallRepo.WithAppId(app.ID), appInstallRepo.WithStatus(constant.Running))
if err != nil {
return nil, err
}
for _, install := range installs {
paramMap := make(map[string]string)
if install.Param != "" {
_ = json.Unmarshal([]byte(install.Param), &paramMap)
}
res = append(res, response.AppService{
Label: install.Name,
Value: install.ServiceName,
Config: paramMap,
})
for _, install := range installs {
paramMap := make(map[string]string)
if install.Param != "" {
_ = json.Unmarshal([]byte(install.Param), &paramMap)
}
res = append(res, response.AppService{
Label: install.Name,
Value: install.ServiceName,
Config: paramMap,
})
}
return res, nil
}
@@ -572,22 +523,22 @@ func (a *AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, erro
return res, nil
}
func (a *AppInstallService) GetDefaultConfigByKey(key, name string) (string, error) {
baseInfo, err := appInstallRepo.LoadBaseInfo(key, name)
func (a *AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
appInstall, err := getAppInstallByKey(key)
if err != nil {
return "", err
}
fileOp := files.NewFileOp()
filePath := path.Join(constant.AppResourceDir, "remote", baseInfo.Key, baseInfo.Version, "conf")
filePath := path.Join(constant.AppResourceDir, "remote", appInstall.App.Key, appInstall.Version, "conf")
if !fileOp.Stat(filePath) {
filePath = path.Join(constant.AppResourceDir, baseInfo.Key, "versions", baseInfo.Version, "conf")
filePath = path.Join(constant.AppResourceDir, appInstall.App.Key, "versions", appInstall.Version, "conf")
}
if !fileOp.Stat(filePath) {
return "", buserr.New(constant.ErrPathNotFound)
}
if key == constant.AppMysql || key == constant.AppMariaDB {
if key == constant.AppMysql {
filePath = path.Join(filePath, "my.cnf")
}
if key == constant.AppRedis {
@@ -675,8 +626,8 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
return &res, nil
}
func syncByID(installID uint) error {
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installID))
func syncById(installId uint) error {
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
if err != nil {
return err
}
@@ -780,7 +731,7 @@ func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value
envKey := ""
switch param {
case "password":
if appKey == "mysql" || appKey == "mariadb" {
if appKey == "mysql" {
envKey = "PANEL_DB_ROOT_PASSWORD="
} else {
envKey = "PANEL_REDIS_ROOT_PASSWORD="
+51 -164
View File
@@ -15,8 +15,6 @@ import (
"strconv"
"strings"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/i18n"
@@ -82,48 +80,11 @@ func checkPort(key string, params map[string]interface{}) (int, error) {
return 0, nil
}
var DatabaseKeys = map[string]uint{
"mysql": 3306,
"mariadb": 3306,
"postgresql": 5432,
"mongodb": 27017,
"redis": 6379,
"memcached": 11211,
}
func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall, params map[string]interface{}) error {
var dbConfig dto.AppDatabase
if app.Type == "runtime" && DatabaseKeys[app.Key] > 0 {
database := &model.Database{
AppInstallID: appInstall.ID,
Name: appInstall.Name,
Type: app.Key,
Version: appInstall.Version,
From: "local",
Address: appInstall.ServiceName,
Port: DatabaseKeys[app.Key],
}
detail, err := appDetailRepo.GetFirst(commonRepo.WithByID(appInstall.AppDetailId))
if err != nil {
return err
}
formFields := &dto.AppForm{}
if err := json.Unmarshal([]byte(detail.Params), formFields); err != nil {
return err
}
for _, form := range formFields.FormFields {
if form.EnvKey == "PANEL_APP_PORT_HTTP" {
portFloat, ok := form.Default.(float64)
if ok {
database.Port = uint(int(portFloat))
}
break
}
}
if app.Type == "runtime" {
switch app.Key {
case "mysql", "mariadb", "postgresql", "mongodb":
case "mysql", "mariadb", "postgresql":
if password, ok := params["PANEL_DB_ROOT_PASSWORD"]; ok {
if password != "" {
authParam := dto.AuthParam{
@@ -134,13 +95,6 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
return err
}
appInstall.Param = string(authByte)
database.Password = password.(string)
if app.Key == "mysql" || app.Key == "mariadb" {
database.Username = "root"
}
if rootUser, ok := params["PANEL_DB_ROOT_USER"]; ok {
database.Username = rootUser.(string)
}
}
}
case "redis":
@@ -155,12 +109,8 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
}
appInstall.Param = string(authByte)
}
database.Password = password.(string)
}
}
if err := databaseRepo.Create(ctx, database); err != nil {
return err
}
}
if app.Type == "website" || app.Type == "tool" {
paramByte, err := json.Marshal(params)
@@ -190,7 +140,6 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
var createMysql dto.MysqlDBCreate
createMysql.Name = dbConfig.DbName
createMysql.Username = dbConfig.DbUser
createMysql.Database = dbInstall.Name
createMysql.Format = "utf8mb4"
createMysql.Permission = "%"
createMysql.Password = dbConfig.Password
@@ -224,7 +173,7 @@ func handleAppInstallErr(ctx context.Context, install *model.AppInstall) error {
return err
}
}
if err := deleteLink(ctx, install, true, true, true); err != nil {
if err := deleteLink(ctx, install, true, true); err != nil {
return err
}
return nil
@@ -239,33 +188,20 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
if err != nil && !forceDelete {
return handleErr(install, err, out)
}
if err = runScript(&install, "uninstall"); err != nil {
_, _ = compose.Up(install.GetComposePath())
return err
}
}
tx, ctx := helper.GetTxAndContext()
defer tx.Rollback()
if err := appInstallRepo.Delete(ctx, install); err != nil {
return err
}
if err := deleteLink(ctx, &install, deleteDB, forceDelete, deleteBackup); err != nil && !forceDelete {
if err := deleteLink(ctx, &install, deleteDB, forceDelete); err != nil && !forceDelete {
return err
}
if DatabaseKeys[install.App.Key] > 0 {
_ = databaseRepo.Delete(ctx, databaseRepo.WithAppInstallID(install.ID))
}
switch install.App.Key {
case constant.AppOpenresty:
_ = websiteRepo.DeleteAll(ctx)
_ = websiteDomainRepo.DeleteAll(ctx)
case constant.AppMysql, constant.AppMariaDB:
_ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name))
}
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name))
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(install.App.Key))
if install.App.Key == constant.AppMysql {
_ = mysqlRepo.DeleteLocal(ctx)
}
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/app/%s/%s", install.App.Key, install.Name))
if _, err := os.Stat(uploadDir); err == nil {
_ = os.RemoveAll(uploadDir)
@@ -283,25 +219,21 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
return nil
}
func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, forceDelete bool, deleteBackup bool) error {
func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, forceDelete bool) error {
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
if len(resources) == 0 {
return nil
}
for _, re := range resources {
mysqlService := NewIMysqlService()
if (re.Key == constant.AppMysql || re.Key == constant.AppMariaDB) && deleteDB {
if re.Key == "mysql" && deleteDB {
database, _ := mysqlRepo.Get(commonRepo.WithByID(re.ResourceId))
if reflect.DeepEqual(database, model.DatabaseMysql{}) {
continue
}
if err := mysqlService.Delete(ctx, dto.MysqlDBDelete{
ID: database.ID,
ForceDelete: forceDelete,
DeleteBackup: deleteBackup,
Type: re.Key,
Database: database.MysqlName,
ID: database.ID,
ForceDelete: forceDelete,
}); err != nil && !forceDelete {
return err
}
@@ -352,19 +284,10 @@ func upgradeInstall(installId uint, detailId uint, backup bool) error {
detailDir = path.Join(constant.ResourceDir, "apps", "local", strings.TrimPrefix(install.App.Key, "local"), detail.Version)
}
command := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
stdout, _ := command.CombinedOutput()
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
stdout, _ := cmd.CombinedOutput()
if stdout != nil {
global.LOG.Infof("upgrade app [%s] [%s] cp file log : %s ", install.App.Key, install.Name, string(stdout))
}
fileOp := files.NewFileOp()
sourceScripts := path.Join(detailDir, "scripts")
if fileOp.Stat(sourceScripts) {
dstScripts := path.Join(install.GetPath(), "scripts")
_ = fileOp.DeleteDir(dstScripts)
_ = fileOp.CreateDir(dstScripts, 0755)
scriptCmd := exec.Command("cp", "-rf", sourceScripts+"/.", dstScripts+"/")
_, _ = scriptCmd.CombinedOutput()
global.LOG.Errorf("upgrade app [%s] [%s] cp file log : %s ", install.App.Key, install.Name, string(stdout))
}
composeMap := make(map[string]interface{})
@@ -377,21 +300,20 @@ func upgradeInstall(installId uint, detailId uint, backup bool) error {
return
}
servicesMap := value.(map[string]interface{})
if len(servicesMap) == 1 {
index := 0
oldServiceName := ""
for k := range servicesMap {
oldServiceName = k
index++
if index > 0 {
break
}
}
servicesMap[install.ServiceName] = servicesMap[oldServiceName]
if install.ServiceName != oldServiceName {
delete(servicesMap, oldServiceName)
index := 0
oldServiceName := ""
for k := range servicesMap {
oldServiceName = k
index++
if index > 0 {
break
}
}
servicesMap[install.ServiceName] = servicesMap[oldServiceName]
if install.ServiceName != oldServiceName {
delete(servicesMap, oldServiceName)
}
envs := make(map[string]interface{})
if upErr = json.Unmarshal([]byte(install.Env), &envs); upErr != nil {
return
@@ -444,16 +366,12 @@ func upgradeInstall(installId uint, detailId uint, backup bool) error {
}
return
}
fileOp := files.NewFileOp()
envParams := make(map[string]string, len(envs))
handleMap(envs, envParams)
if err = env.Write(envParams, install.GetEnvPath()); err != nil {
return
}
if err = runScript(&install, "upgrade"); err != nil {
return
}
if upErr = fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); upErr != nil {
return
}
@@ -557,8 +475,6 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
envParams[k] = t
case float64:
envParams[k] = strconv.FormatFloat(t, 'f', -1, 32)
case uint:
envParams[k] = strconv.Itoa(int(t))
default:
envParams[k] = t.(string)
}
@@ -580,7 +496,7 @@ func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.App
_ = fileOp.CreateDir(appVersionDir, 0755)
}
global.LOG.Infof("download app[%s] from %s", app.Name, appDetail.DownloadUrl)
filePath := path.Join(appVersionDir, app.Key+"-"+appDetail.Version+".tar.gz")
filePath := path.Join(appVersionDir, appDetail.Version+".tar.gz")
defer func() {
if err != nil {
@@ -595,7 +511,7 @@ func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.App
global.LOG.Errorf("download app[%s] error %v", app.Name, err)
return
}
if err = fileOp.Decompress(filePath, appResourceDir, files.TarGz); err != nil {
if err = fileOp.Decompress(filePath, appVersionDir, files.TarGz); err != nil {
global.LOG.Errorf("decompress app[%s] error %v", app.Name, err)
return
}
@@ -658,28 +574,17 @@ func copyData(app model.App, appDetail model.AppDetail, appInstall *model.AppIns
return
}
func runScript(appInstall *model.AppInstall, operate string) error {
workDir := appInstall.GetPath()
scriptPath := ""
switch operate {
case "init":
scriptPath = path.Join(workDir, "scripts", "init.sh")
case "upgrade":
scriptPath = path.Join(workDir, "scripts", "upgrade.sh")
case "uninstall":
scriptPath = path.Join(workDir, "scripts", "uninstall.sh")
}
if !files.NewFileOp().Stat(scriptPath) {
return nil
}
out, err := cmd.ExecScript(scriptPath, workDir)
if err != nil {
if out != "" {
errMsg := fmt.Sprintf("run script %s error %s", scriptPath, out)
global.LOG.Error(errMsg)
return errors.New(errMsg)
}
return err
// 处理文件夹权限等问题
func upAppPre(app model.App, appInstall *model.AppInstall) error {
dataPath := path.Join(appInstall.GetPath(), "data")
fileOp := files.NewFileOp()
switch app.Key {
case "nexus":
return fileOp.ChownR(dataPath, "200", "0", true)
case "sftpgo":
return fileOp.ChownR(dataPath, "1000", "1000", true)
case "pgadmin4":
return fileOp.ChownR(dataPath, "5050", "5050", true)
}
return nil
}
@@ -755,24 +660,16 @@ func upApp(appInstall *model.AppInstall) {
}
func rebuildApp(appInstall model.AppInstall) error {
appInstall.Status = constant.Rebuilding
_ = appInstallRepo.Save(context.Background(), &appInstall)
go func() {
dockerComposePath := appInstall.GetComposePath()
out, err := compose.Down(dockerComposePath)
if err != nil {
_ = handleErr(appInstall, err, out)
return
}
out, err = compose.Up(dockerComposePath)
if err != nil {
_ = handleErr(appInstall, err, out)
return
}
appInstall.Status = constant.Running
_ = appInstallRepo.Save(context.Background(), &appInstall)
}()
return nil
dockerComposePath := appInstall.GetComposePath()
out, err := compose.Down(dockerComposePath)
if err != nil {
return handleErr(appInstall, err, out)
}
out, err = compose.Up(dockerComposePath)
if err != nil {
return handleErr(appInstall, err, out)
}
return syncById(appInstall.ID)
}
func getAppDetails(details []model.AppDetail, versions []dto.AppConfigVersion) map[string]model.AppDetail {
@@ -978,16 +875,6 @@ func getAppInstallByKey(key string) (model.AppInstall, error) {
return appInstall, nil
}
func getAppInstallPort(key string) (httpPort, httpsPort int, err error) {
install, err := getAppInstallByKey(key)
if err != nil {
return
}
httpPort = install.HttpPort
httpsPort = install.HttpsPort
return
}
func updateToolApp(installed *model.AppInstall) {
tooKey, ok := dto.AppToolMap[installed.App.Key]
if !ok {
+5 -19
View File
@@ -4,7 +4,6 @@ import (
"strconv"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
@@ -20,16 +19,16 @@ type AuthService struct{}
type IAuthService interface {
CheckIsSafety(code string) (string, error)
VerifyCode(code string) (bool, error)
Login(c *gin.Context, info dto.Login, entrance string) (*dto.UserLoginInfo, error)
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error)
LogOut(c *gin.Context) error
MFALogin(c *gin.Context, info dto.MFALogin, entrance string) (*dto.UserLoginInfo, error)
MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLoginInfo, error)
}
func NewIAuthService() IAuthService {
return &AuthService{}
}
func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*dto.UserLoginInfo, error) {
func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error) {
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
@@ -45,13 +44,6 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*d
if info.Password != pass || nameSetting.Value != info.Name {
return nil, constant.ErrAuth
}
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
if err != nil {
return nil, err
}
if len(entranceSetting.Value) != 0 && entranceSetting.Value != entrance {
return nil, buserr.New(constant.ErrEntrance)
}
mfa, err := settingRepo.Get(settingRepo.WithByKey("MFAStatus"))
if err != nil {
return nil, err
@@ -65,7 +57,7 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*d
return u.generateSession(c, info.Name, info.AuthMethod)
}
func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance string) (*dto.UserLoginInfo, error) {
func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLoginInfo, error) {
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
@@ -81,13 +73,7 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance strin
if info.Password != pass || nameSetting.Value != info.Name {
return nil, constant.ErrAuth
}
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
if err != nil {
return nil, err
}
if len(entranceSetting.Value) != 0 && entranceSetting.Value != entrance {
return nil, buserr.New(constant.ErrEntrance)
}
mfaSecret, err := settingRepo.Get(settingRepo.WithByKey("MFASecret"))
if err != nil {
return nil, err
+6 -14
View File
@@ -106,7 +106,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
for _, resource := range resources {
if resource.Key == "mysql" || resource.Key == "mariadb" {
if resource.Key == "mysql" {
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
if err != nil {
return err
@@ -173,15 +173,8 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
newEnvFile := ""
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
for _, resource := range resources {
if resource.From != "local" {
continue
}
resourceApp, err := appInstallRepo.GetFirst(commonRepo.WithByID(resource.LinkId))
if err != nil {
return err
}
if resource.Key == "mysql" || resource.Key == "mariadb" {
mysqlInfo, err := appInstallRepo.LoadBaseInfo(resource.Key, resourceApp.Name)
if resource.Key == "mysql" {
mysqlInfo, err := appInstallRepo.LoadBaseInfo(resource.Key, "")
if err != nil {
return err
}
@@ -190,7 +183,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
return err
}
newDB, envMap, err := reCreateDB(db.ID, resourceApp, oldInstall.Env)
newDB, envMap, err := reCreateDB(db.ID, oldInstall.Env)
if err != nil {
return err
}
@@ -252,10 +245,10 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
return nil
}
func reCreateDB(dbID uint, app model.AppInstall, oldEnv string) (*model.DatabaseMysql, map[string]interface{}, error) {
func reCreateDB(dbID uint, oldEnv string) (*model.DatabaseMysql, map[string]interface{}, error) {
mysqlService := NewIMysqlService()
ctx := context.Background()
_ = mysqlService.Delete(ctx, dto.MysqlDBDelete{ID: dbID, Database: app.Name, Type: app.App.Key, DeleteBackup: true, ForceDelete: true})
_ = mysqlService.Delete(ctx, dto.MysqlDBDelete{ID: dbID, DeleteBackup: true, ForceDelete: true})
envMap := make(map[string]interface{})
if err := json.Unmarshal([]byte(oldEnv), &envMap); err != nil {
@@ -267,7 +260,6 @@ func reCreateDB(dbID uint, app model.AppInstall, oldEnv string) (*model.Database
createDB, err := mysqlService.Create(context.Background(), dto.MysqlDBCreate{
Name: oldName,
From: "local",
Database: app.Name,
Format: "utf8mb4",
Username: oldUser,
Password: oldPassword,
+7 -7
View File
@@ -23,7 +23,7 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
}
timeNow := time.Now().Format("20060102150405")
targetDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", req.Type, req.Name, req.DetailName))
targetDir := path.Join(localDir, fmt.Sprintf("database/mysql/%s/%s", req.Name, req.DetailName))
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow)
if err := handleMysqlBackup(req.Name, req.DetailName, targetDir, fileName); err != nil {
@@ -31,7 +31,7 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
}
record := &model.BackupRecord{
Type: req.Type,
Type: "mysql",
Name: req.Name,
DetailName: req.DetailName,
Source: "LOCAL",
@@ -97,12 +97,12 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error {
return nil
}
func handleMysqlBackup(database, dbName, targetDir, fileName string) error {
dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(dbName), mysqlRepo.WithByMysqlName(database))
func handleMysqlBackup(name, dbName, targetDir, fileName string) error {
dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(dbName), mysqlRepo.WithByMysqlName(name))
if err != nil {
return err
}
cli, _, err := LoadMysqlClientByFrom(database)
cli, _, err := LoadMysqlClientByFrom(dbInfo.From)
if err != nil {
return err
}
@@ -131,13 +131,13 @@ func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error {
if err != nil {
return err
}
cli, _, err := LoadMysqlClientByFrom(req.Name)
cli, _, err := LoadMysqlClientByFrom(dbInfo.From)
if err != nil {
return err
}
if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format("20060102150405")))
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/mysql/%s_%s.sql.gz", req.DetailName, time.Now().Format("20060102150405")))
if err := cli.Backup(client.BackupInfo{
Name: req.DetailName,
Format: dbInfo.Format,
+9 -66
View File
@@ -147,7 +147,14 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
IsFromApp = true
}
ports := simplifyPort(item.Ports)
var ports []string
for _, port := range item.Ports {
itemPortStr := fmt.Sprintf("%v/%s", port.PrivatePort, port.Type)
if port.PublicPort != 0 {
itemPortStr = fmt.Sprintf("%s:%v->%v/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type)
}
ports = append(ports, itemPortStr)
}
backDatas[i] = dto.ContainerInfo{
ContainerID: item.ID,
CreateTime: time.Unix(item.Created, 0).Format("2006-01-02 15:04:05"),
@@ -160,14 +167,6 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
IsFromApp: IsFromApp,
IsFromCompose: IsFromCompose,
}
if item.NetworkSettings != nil && len(item.NetworkSettings.Networks) > 0 {
networks := make([]string, 0, len(item.NetworkSettings.Networks))
for key := range item.NetworkSettings.Networks {
networks = append(networks, item.NetworkSettings.Networks[key].IPAddress)
}
sort.Strings(networks)
backDatas[i].Network = networks
}
}
return int64(total), backDatas, nil
@@ -366,7 +365,6 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
}
}
data.Cmd = oldContainer.Config.Cmd
data.Entrypoint = oldContainer.Config.Entrypoint
data.Env = oldContainer.Config.Env
data.CPUShares = oldContainer.HostConfig.CPUShares
for key, val := range oldContainer.Config.Labels {
@@ -568,7 +566,7 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, container, sinc
}
command := fmt.Sprintf("docker logs %s", container)
if tail != "0" {
command += " --tail " + tail
command += " -n " + tail
}
if since != "all" {
command += " --since " + since
@@ -843,7 +841,6 @@ func loadConfigInfo(req dto.ContainerOperate, config *container.Config, hostConf
}
config.Image = req.Image
config.Cmd = req.Cmd
config.Entrypoint = req.Entrypoint
config.Env = req.Env
config.Labels = stringsToMap(req.Labels)
config.ExposedPorts = exposeds
@@ -932,57 +929,3 @@ func loadVolumeBinds(binds []string) []dto.VolumeHelper {
}
return datas
}
func simplifyPort(ports []types.Port) []string {
var datas []string
if len(ports) == 0 {
return datas
}
if len(ports) == 1 {
itemPortStr := fmt.Sprintf("%s:%v/%s", ports[0].IP, ports[0].PrivatePort, ports[0].Type)
if ports[0].PublicPort != 0 {
itemPortStr = fmt.Sprintf("%s:%v->%v/%s", ports[0].IP, ports[0].PublicPort, ports[0].PrivatePort, ports[0].Type)
}
datas = append(datas, itemPortStr)
return datas
}
sort.Slice(ports, func(i, j int) bool {
return ports[i].PrivatePort < ports[j].PrivatePort
})
start := ports[0]
for i := 1; i < len(ports); i++ {
if ports[i].PrivatePort != ports[i-1].PrivatePort+1 || ports[i].IP != ports[i-1].IP || ports[i].PublicPort != ports[i-1].PublicPort+1 || ports[i].Type != ports[i-1].Type {
if ports[i-1].PrivatePort == start.PrivatePort {
itemPortStr := fmt.Sprintf("%s:%v/%s", start.IP, start.PrivatePort, start.Type)
if start.PublicPort != 0 {
itemPortStr = fmt.Sprintf("%s:%v->%v/%s", start.IP, start.PublicPort, start.PrivatePort, start.Type)
}
datas = append(datas, itemPortStr)
} else {
itemPortStr := fmt.Sprintf("%s:%v-%v/%s", start.IP, start.PrivatePort, ports[i-1].PrivatePort, start.Type)
if start.PublicPort != 0 {
itemPortStr = fmt.Sprintf("%s:%v-%v->%v-%v/%s", start.IP, start.PublicPort, ports[i-1].PublicPort, start.PrivatePort, ports[i-1].PrivatePort, start.Type)
}
datas = append(datas, itemPortStr)
}
start = ports[i]
} else if i == len(ports)-1 {
if ports[i].PrivatePort == start.PrivatePort {
itemPortStr := fmt.Sprintf("%s:%v/%s", start.IP, start.PrivatePort, start.Type)
if start.PublicPort != 0 {
itemPortStr = fmt.Sprintf("%s:%v->%v/%s", start.IP, start.PublicPort, start.PrivatePort, start.Type)
}
datas = append(datas, itemPortStr)
} else {
itemPortStr := fmt.Sprintf("%s:%v-%v/%s", start.IP, start.PrivatePort, ports[i].PrivatePort, start.Type)
if start.PublicPort != 0 {
itemPortStr = fmt.Sprintf("%s:%v-%v->%v-%v/%s", start.IP, start.PublicPort, ports[i].PublicPort, start.PrivatePort, ports[i].PrivatePort, start.Type)
}
datas = append(datas, itemPortStr)
}
}
}
return datas
}
+2 -3
View File
@@ -46,7 +46,7 @@ func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, inter
if err := copier.Copy(&item, &cronjob); err != nil {
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
if item.Type == "app" || item.Type == "website" || item.Type == "database" || item.Type == "directory" || item.Type == "snapshot" {
if item.Type == "website" || item.Type == "database" || item.Type == "directory" {
backup, _ := backupRepo.Get(commonRepo.WithByID(uint(item.TargetDirID)))
if len(backup.Type) != 0 {
item.TargetDir = backup.Type
@@ -103,7 +103,7 @@ func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
if err != nil {
return err
}
if req.CleanData && (cronjob.Type == "app" || cronjob.Type == "database" || cronjob.Type == "website" || cronjob.Type == "directory" || cronjob.Type == "snapshot") {
if req.CleanData && (cronjob.Type == "database" || cronjob.Type == "website" || cronjob.Type == "directory") {
cronjob.RetainCopies = 0
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
if err != nil {
@@ -261,7 +261,6 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
upMap["hour"] = req.Hour
upMap["minute"] = req.Minute
upMap["second"] = req.Second
upMap["app_id"] = req.AppID
upMap["website"] = req.Website
upMap["exclusion_rules"] = req.ExclusionRules
upMap["db_name"] = req.DBName
+7 -120
View File
@@ -10,7 +10,6 @@ import (
"sync"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
@@ -39,10 +38,6 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
message, err = u.handleShell(cronjob.Type, cronjob.Name, cronjob.Script)
}
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
case "snapshot":
messageItem := ""
messageItem, record.File, err = u.handleSnapshot(cronjob, record.StartTime)
message = []byte(messageItem)
case "curl":
if len(cronjob.URL) == 0 {
return
@@ -52,7 +47,9 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
case "ntp":
err = u.handleNtpSync()
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
case "website", "database", "app":
case "website":
record.File, err = u.handleBackup(cronjob, record.StartTime)
case "database":
record.File, err = u.handleBackup(cronjob, record.StartTime)
case "directory":
if len(cronjob.SourceDir) == 0 {
@@ -65,7 +62,6 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
global.LOG.Errorf("cut website log file failed, err: %v", err)
}
}
if err != nil {
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), string(message))
return
@@ -89,7 +85,7 @@ func (u *CronjobService) handleShell(cronType, cornName, script string) ([]byte,
}
stdout, err := cmd.ExecCronjobWithTimeOut(script, handleDir, 24*time.Hour)
if err != nil {
return []byte(stdout), err
return nil, err
}
return []byte(stdout), nil
}
@@ -124,9 +120,6 @@ func (u *CronjobService) handleBackup(cronjob *model.Cronjob, startTime time.Tim
case "database":
paths, err := u.handleDatabase(*cronjob, backup, startTime)
return strings.Join(paths, ","), err
case "app":
paths, err := u.handleApp(*cronjob, backup, startTime)
return strings.Join(paths, ","), err
case "website":
paths, err := u.handleWebsite(*cronjob, backup, startTime)
return strings.Join(paths, ","), err
@@ -193,10 +186,6 @@ func (u *CronjobService) HandleRmExpired(backType, backupPath, localDir string,
fileItem = strings.TrimPrefix(file, localDir+"/")
}
}
if cronjob.Type == "snapshot" {
_ = snapshotRepo.Delete(commonRepo.WithByName(strings.TrimSuffix(path.Base(fileItem), ".tar.gz")))
}
_, _ = backClient.Delete(fileItem)
}
}
@@ -232,7 +221,7 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error {
path = sourceDir
}
commands := fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s", targetDir+"/"+name, excludeRules, path)
commands := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s %s", targetDir+"/"+name, excludeRules, path)
global.LOG.Debug(commands)
stdout, err := cmd.ExecWithTimeOut(commands, 24*time.Hour)
if err != nil {
@@ -293,13 +282,12 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, backup model.Back
for _, dbInfo := range dbs {
var record model.BackupRecord
database, _ := databaseRepo.Get(commonRepo.WithByName(dbInfo.MysqlName))
record.Type = database.Type
record.Type = "mysql"
record.Source = "LOCAL"
record.BackupType = backup.Type
record.Name = dbInfo.MysqlName
backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", database.Type, record.Name, dbInfo.Name))
backupDir := path.Join(localDir, fmt.Sprintf("database/mysql/%s/%s", record.Name, dbInfo.Name))
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format("20060102150405"))
if err = handleMysqlBackup(dbInfo.MysqlName, dbInfo.Name, backupDir, record.FileName); err != nil {
return paths, err
@@ -408,83 +396,6 @@ func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime t
return strings.Join(filePaths, ","), nil
}
func (u *CronjobService) handleApp(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
var paths []string
localDir, err := loadLocalDir()
if err != nil {
return paths, err
}
var applist []model.AppInstall
if cronjob.AppID == "all" {
applist, err = appInstallRepo.ListBy()
if err != nil {
return paths, err
}
} else {
itemID, _ := (strconv.Atoi(cronjob.AppID))
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(uint(itemID)))
if err != nil {
return paths, err
}
applist = append(applist, app)
}
var client cloud_storage.CloudStorageClient
if backup.Type != "LOCAL" {
client, err = NewIBackupService().NewClient(&backup)
if err != nil {
return paths, err
}
}
for _, app := range applist {
var record model.BackupRecord
record.Type = "app"
record.Name = app.App.Key
record.DetailName = app.Name
record.Source = "LOCAL"
record.BackupType = backup.Type
backupDir := path.Join(localDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
record.FileDir = backupDir
itemFileDir := strings.TrimPrefix(backupDir, localDir+"/")
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
record.Source = backup.Type
record.FileDir = strings.TrimPrefix(backupDir, localDir+"/")
}
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format("20060102150405"))
if err := handleAppBackup(&app, backupDir, record.FileName); err != nil {
return paths, err
}
if err := backupRepo.CreateRecord(&record); err != nil {
global.LOG.Errorf("save backup record failed, err: %v", err)
return paths, err
}
if backup.Type != "LOCAL" {
if !cronjob.KeepLocal {
defer func() {
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
}()
}
if len(backup.BackupPath) != 0 {
itemPath := strings.TrimPrefix(backup.BackupPath, "/")
itemPath = strings.TrimSuffix(itemPath, "/") + "/"
itemFileDir = itemPath + itemFileDir
}
if _, err = client.Upload(backupDir+"/"+record.FileName, itemFileDir+"/"+record.FileName); err != nil {
return paths, err
}
}
if backup.Type == "LOCAL" || cronjob.KeepLocal {
paths = append(paths, fmt.Sprintf("%s/%s", record.FileDir, record.FileName))
} else {
paths = append(paths, fmt.Sprintf("%s/%s", itemFileDir, record.FileName))
}
}
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, &cronjob, client)
return paths, nil
}
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
var paths []string
localDir, err := loadLocalDir()
@@ -560,27 +471,3 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.Backu
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, &cronjob, client)
return paths, nil
}
func (u *CronjobService) handleSnapshot(cronjob *model.Cronjob, startTime time.Time) (string, string, error) {
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
if err != nil {
return "", "", err
}
client, err := NewIBackupService().NewClient(&backup)
if err != nil {
return "", "", err
}
req := dto.SnapshotCreate{
From: backup.Type,
}
message, name, err := NewISnapshotService().HandleSnapshot(true, req, startTime.Format("20060102150405"))
if err != nil {
return message, "", err
}
path := path.Join(strings.TrimPrefix(backup.BackupPath, "/"), "system_snapshot", name+".tar.gz")
u.HandleRmExpired(backup.Type, backup.BackupPath, "", cronjob, client)
return message, path, nil
}
+98 -96
View File
@@ -21,7 +21,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"github.com/1Panel-dev/1Panel/backend/utils/mysql"
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
_ "github.com/go-sql-driver/mysql"
@@ -35,19 +34,18 @@ type IMysqlService interface {
SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error)
ListDBOption() ([]dto.MysqlOption, error)
Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error)
LoadFromRemote(req dto.MysqlLoadDB) error
LoadFromRemote(from string) error
ChangeAccess(info dto.ChangeDBInfo) error
ChangePassword(info dto.ChangeDBInfo) error
UpdateVariables(req dto.MysqlVariablesUpdate) error
UpdateVariables(updates []dto.MysqlVariablesUpdate) error
UpdateConfByFile(info dto.MysqlConfUpdateByFile) error
UpdateDescription(req dto.UpdateDescription) error
DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error)
DeleteCheck(id uint) ([]string, error)
Delete(ctx context.Context, req dto.MysqlDBDelete) error
LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error)
LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error)
LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error)
LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error)
LoadStatus() (*dto.MysqlStatus, error)
LoadVariables() (*dto.MysqlVariables, error)
LoadBaseInfo() (*dto.DBBaseInfo, error)
LoadRemoteAccess() (bool, error)
LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error)
}
@@ -58,7 +56,7 @@ func NewIMysqlService() IMysqlService {
func (u *MysqlService) SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error) {
total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize,
mysqlRepo.WithByMysqlName(search.Database),
mysqlRepo.WithByFrom(search.From),
commonRepo.WithLikeName(search.Info),
commonRepo.WithOrderRuleBy(search.OrderBy, search.Order),
)
@@ -75,26 +73,12 @@ func (u *MysqlService) SearchWithPage(search dto.MysqlDBSearch) (int64, interfac
func (u *MysqlService) ListDBOption() ([]dto.MysqlOption, error) {
mysqls, err := mysqlRepo.List()
if err != nil {
return nil, err
}
databases, err := databaseRepo.GetList(databaseRepo.WithTypeList("mysql,mariadb"))
if err != nil {
return nil, err
}
var dbs []dto.MysqlOption
for _, mysql := range mysqls {
var item dto.MysqlOption
if err := copier.Copy(&item, &mysql); err != nil {
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
item.Database = mysql.MysqlName
for _, database := range databases {
if database.Name == item.Database {
item.Type = database.Type
}
}
dbs = append(dbs, item)
}
return dbs, err
@@ -105,7 +89,7 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
return nil, buserr.New(constant.ErrCmdIllegal)
}
mysql, _ := mysqlRepo.Get(commonRepo.WithByName(req.Name), mysqlRepo.WithByMysqlName(req.Database), databaseRepo.WithByFrom(req.From))
mysql, _ := mysqlRepo.Get(commonRepo.WithByName(req.Name), remoteDBRepo.WithByFrom(req.From))
if mysql.ID != 0 {
return nil, constant.ErrRecordExist
}
@@ -119,11 +103,20 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
return nil, errors.New("Cannot set root as user name")
}
cli, version, err := LoadMysqlClientByFrom(req.Database)
cli, version, err := LoadMysqlClientByFrom(req.From)
if err != nil {
return nil, err
}
createItem.MysqlName = req.Database
if req.From == "local" {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return nil, err
}
createItem.MysqlName = app.Name
} else {
createItem.MysqlName = req.From
}
defer cli.Close()
if err := cli.Create(client.CreateInfo{
Name: req.Name,
@@ -144,13 +137,22 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
return &createItem, nil
}
func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error {
client, version, err := LoadMysqlClientByFrom(req.Database)
func (u *MysqlService) LoadFromRemote(from string) error {
client, version, err := LoadMysqlClientByFrom(from)
if err != nil {
return err
}
databases, err := mysqlRepo.List(databaseRepo.WithByFrom(req.From))
mysqlName := from
if from == "local" {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err
}
mysqlName = app.Name
}
databases, err := mysqlRepo.List(remoteDBRepo.WithByFrom(from))
if err != nil {
return err
}
@@ -161,7 +163,7 @@ func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error {
for _, data := range datas {
hasOld := false
for _, oldData := range databases {
if strings.EqualFold(oldData.Name, data.Name) && strings.EqualFold(oldData.MysqlName, data.MysqlName) {
if strings.EqualFold(oldData.Name, data.Name) {
hasOld = true
break
}
@@ -171,6 +173,7 @@ func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error {
if err := copier.Copy(&createItem, &data); err != nil {
return errors.WithMessage(constant.ErrStructTransform, err.Error())
}
createItem.MysqlName = mysqlName
if err := mysqlRepo.Create(context.Background(), &createItem); err != nil {
return err
}
@@ -183,15 +186,15 @@ func (u *MysqlService) UpdateDescription(req dto.UpdateDescription) error {
return mysqlRepo.Update(req.ID, map[string]interface{}{"description": req.Description})
}
func (u *MysqlService) DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error) {
func (u *MysqlService) DeleteCheck(id uint) ([]string, error) {
var appInUsed []string
db, err := mysqlRepo.Get(commonRepo.WithByID(req.ID))
db, err := mysqlRepo.Get(commonRepo.WithByID(id))
if err != nil {
return appInUsed, err
}
if db.From == "local" {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return appInUsed, err
}
@@ -220,7 +223,7 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
if err != nil && !req.ForceDelete {
return err
}
cli, version, err := LoadMysqlClientByFrom(req.Database)
cli, version, err := LoadMysqlClientByFrom(db.From)
if err != nil {
return err
}
@@ -231,11 +234,16 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
Username: db.Username,
Permission: db.Permission,
Timeout: 300,
}); err != nil && !req.ForceDelete {
}); err != nil {
return err
}
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/database/%s/%s/%s", req.Type, req.Database, db.Name))
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil && !req.ForceDelete {
return err
}
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/database/mysql/%s/%s", app.Name, db.Name))
if _, err := os.Stat(uploadDir); err == nil {
_ = os.RemoveAll(uploadDir)
}
@@ -244,23 +252,23 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
if err != nil && !req.ForceDelete {
return err
}
backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", req.Type, db.MysqlName, db.Name))
backupDir := path.Join(localDir, fmt.Sprintf("database/mysql/%s/%s", db.MysqlName, db.Name))
if _, err := os.Stat(backupDir); err == nil {
_ = os.RemoveAll(backupDir)
}
global.LOG.Infof("delete database %s-%s backups successful", req.Database, db.Name)
global.LOG.Infof("delete database %s-%s backups successful", app.Name, db.Name)
}
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(req.Type), commonRepo.WithByName(req.Database), backupRepo.WithByDetailName(db.Name))
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("mysql"), commonRepo.WithByName(app.Name), backupRepo.WithByDetailName(db.Name))
_ = mysqlRepo.Delete(ctx, commonRepo.WithByID(db.ID))
return nil
}
func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error {
if cmd.CheckIllegal(req.Value) {
func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error {
if cmd.CheckIllegal(info.Value) {
return buserr.New(constant.ErrCmdIllegal)
}
cli, version, err := LoadMysqlClientByFrom(req.Database)
cli, version, err := LoadMysqlClientByFrom(info.From)
if err != nil {
return err
}
@@ -269,12 +277,12 @@ func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error {
mysqlData model.DatabaseMysql
passwordInfo client.PasswordChangeInfo
)
passwordInfo.Password = req.Value
passwordInfo.Password = info.Value
passwordInfo.Timeout = 300
passwordInfo.Version = version
if req.ID != 0 {
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(req.ID))
if info.ID != 0 {
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(info.ID))
if err != nil {
return err
}
@@ -288,10 +296,10 @@ func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error {
return err
}
if req.ID != 0 {
if info.ID != 0 {
var appRess []model.AppInstallResource
if req.From == "local" {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
if info.From == "local" {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err
}
@@ -310,30 +318,29 @@ func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error {
}
global.LOG.Infof("start to update mysql password used by app %s-%s", appModel.Key, appInstall.Name)
if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", true, req.Value); err != nil {
if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", true, info.Value); err != nil {
return err
}
}
global.LOG.Info("execute password change sql successful")
pass, err := encrypt.StringEncrypt(req.Value)
if err != nil {
return fmt.Errorf("decrypt database db password failed, err: %v", err)
}
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"password": pass})
global.LOG.Info("excute password change sql successful")
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"password": info.Value})
return nil
}
if err := updateInstallInfoInDB(req.Type, req.Database, "password", false, req.Value); err != nil {
if err := updateInstallInfoInDB("mysql", "", "password", false, info.Value); err != nil {
return err
}
if err := updateInstallInfoInDB("phpmyadmin", "", "password", true, info.Value); err != nil {
return err
}
return nil
}
func (u *MysqlService) ChangeAccess(req dto.ChangeDBInfo) error {
if cmd.CheckIllegal(req.Value) {
func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
if cmd.CheckIllegal(info.Value) {
return buserr.New(constant.ErrCmdIllegal)
}
cli, version, err := LoadMysqlClientByFrom(req.Database)
cli, version, err := LoadMysqlClientByFrom(info.From)
if err != nil {
return err
}
@@ -342,12 +349,12 @@ func (u *MysqlService) ChangeAccess(req dto.ChangeDBInfo) error {
mysqlData model.DatabaseMysql
accessInfo client.AccessChangeInfo
)
accessInfo.Permission = req.Value
accessInfo.Permission = info.Value
accessInfo.Timeout = 300
accessInfo.Version = version
if req.ID != 0 {
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(req.ID))
if info.ID != 0 {
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(info.ID))
if err != nil {
return err
}
@@ -363,40 +370,40 @@ func (u *MysqlService) ChangeAccess(req dto.ChangeDBInfo) error {
}
if mysqlData.ID != 0 {
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"permission": req.Value})
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"permission": info.Value})
}
return nil
}
func (u *MysqlService) UpdateConfByFile(req dto.MysqlConfUpdateByFile) error {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
func (u *MysqlService) UpdateConfByFile(info dto.MysqlConfUpdateByFile) error {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err
}
path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, app.Name)
path := fmt.Sprintf("%s/mysql/%s/conf/my.cnf", constant.AppInstallDir, app.Name)
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(req.File)
_, _ = write.WriteString(info.File)
write.Flush()
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil {
if _, err := compose.Restart(fmt.Sprintf("%s/mysql/%s/docker-compose.yml", constant.AppInstallDir, app.Name)); err != nil {
return err
}
return nil
}
func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
func (u *MysqlService) UpdateVariables(updates []dto.MysqlVariablesUpdate) error {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err
}
var files []string
path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, app.Name)
path := fmt.Sprintf("%s/mysql/%s/conf/my.cnf", constant.AppInstallDir, app.Name)
lineBytes, err := os.ReadFile(path)
if err != nil {
return err
@@ -404,7 +411,7 @@ func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error {
files = strings.Split(string(lineBytes), "\n")
group := "[mysqld]"
for _, info := range req.Variables {
for _, info := range updates {
if !strings.HasPrefix(app.Version, "5.7") && !strings.HasPrefix(app.Version, "5.6") {
if info.Param == "query_cache_size" {
continue
@@ -427,16 +434,16 @@ func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error {
return err
}
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil {
if _, err := compose.Restart(fmt.Sprintf("%s/mysql/%s/docker-compose.yml", constant.AppInstallDir, app.Name)); err != nil {
return err
}
return nil
}
func (u *MysqlService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error) {
func (u *MysqlService) LoadBaseInfo() (*dto.DBBaseInfo, error) {
var data dto.DBBaseInfo
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return nil, err
}
@@ -447,8 +454,8 @@ func (u *MysqlService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBa
return &data, nil
}
func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error) {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
func (u *MysqlService) LoadRemoteAccess() (bool, error) {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return false, err
}
@@ -465,8 +472,8 @@ func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool,
return false, nil
}
func (u *MysqlService) LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error) {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
func (u *MysqlService) LoadVariables() (*dto.MysqlVariables, error) {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return nil, err
}
@@ -483,8 +490,8 @@ func (u *MysqlService) LoadVariables(req dto.OperationWithNameAndType) (*dto.Mys
return &info, nil
}
func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error) {
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return nil, err
}
@@ -533,14 +540,10 @@ func (u *MysqlService) LoadDatabaseFile(req dto.OperationWithNameAndType) (strin
switch req.Type {
case "mysql-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/conf/my.cnf", req.Name))
case "mariadb-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/conf/my.cnf", req.Name))
case "redis-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
case "mysql-slow-logs":
case "slow-logs":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
case "mariadb-slow-logs":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name))
}
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
@@ -622,21 +625,20 @@ func updateMyCnf(oldFiles []string, group string, param string, value interface{
return newFiles
}
func LoadMysqlClientByFrom(database string) (mysql.MysqlClient, string, error) {
func LoadMysqlClientByFrom(from string) (mysql.MysqlClient, string, error) {
var (
dbInfo client.DBInfo
version string
err error
)
dbInfo.From = from
dbInfo.Timeout = 300
databaseItem, err := databaseRepo.Get(commonRepo.WithByName(database))
if err != nil {
return nil, "", err
}
dbInfo.From = databaseItem.From
dbInfo.Database = database
if dbInfo.From != "local" {
if from != "local" {
databaseItem, err := remoteDBRepo.Get(commonRepo.WithByName(from))
if err != nil {
return nil, "", err
}
dbInfo.Address = databaseItem.Address
dbInfo.Port = databaseItem.Port
dbInfo.Username = databaseItem.Username
@@ -644,7 +646,7 @@ func LoadMysqlClientByFrom(database string) (mysql.MysqlClient, string, error) {
version = databaseItem.Version
} else {
app, err := appInstallRepo.LoadBaseInfo(databaseItem.Type, database)
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return nil, "", err
}
+2 -2
View File
@@ -21,7 +21,7 @@ type RedisService struct{}
type IRedisService interface {
UpdateConf(req dto.RedisConfUpdate) error
UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error
ChangePassword(info dto.ChangeRedisPass) error
ChangePassword(info dto.ChangeDBInfo) error
LoadStatus() (*dto.RedisStatus, error)
LoadConf() (*dto.RedisConf, error)
@@ -54,7 +54,7 @@ func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
return nil
}
func (u *RedisService) ChangePassword(req dto.ChangeRedisPass) error {
func (u *RedisService) ChangePassword(req dto.ChangeDBInfo) error {
if err := updateInstallInfoInDB("redis", "", "password", true, req.Value); err != nil {
return err
}
+1 -1
View File
@@ -13,7 +13,7 @@ var (
appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
mysqlRepo = repo.NewIMysqlRepo()
databaseRepo = repo.NewIDatabaseRepo()
remoteDBRepo = repo.NewIRemoteDBRepo()
imageRepoRepo = repo.NewIImageRepoRepo()
composeRepo = repo.NewIComposeTemplateRepo()
+41 -213
View File
@@ -5,18 +5,14 @@ import (
"os"
"strconv"
"strings"
"sync"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/firewall"
fireClient "github.com/1Panel-dev/1Panel/backend/utils/firewall/client"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
)
const confPath = "/etc/sysctl.conf"
@@ -31,7 +27,6 @@ type IFirewallService interface {
OperateAddressRule(req dto.AddrRuleOperate, reload bool) error
UpdatePortRule(req dto.PortRuleUpdate) error
UpdateAddrRule(req dto.AddrRuleUpdate) error
UpdateDescription(req dto.UpdateFirewallDescription) error
BatchOperateRule(req dto.BatchRuleOperate) error
}
@@ -41,6 +36,7 @@ func NewIFirewallService() IFirewallService {
func (u *FirewallService) LoadBaseInfo() (dto.FirewallBaseInfo, error) {
var baseInfo dto.FirewallBaseInfo
baseInfo.PingStatus = u.pingStatus()
baseInfo.Status = "not running"
baseInfo.Version = "-"
baseInfo.Name = "-"
@@ -52,22 +48,17 @@ func (u *FirewallService) LoadBaseInfo() (dto.FirewallBaseInfo, error) {
return baseInfo, err
}
baseInfo.Name = client.Name()
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
baseInfo.PingStatus = u.pingStatus()
}()
go func() {
defer wg.Done()
baseInfo.Status, _ = client.Status()
}()
go func() {
defer wg.Done()
baseInfo.Version, _ = client.Version()
}()
wg.Wait()
baseInfo.Status, err = client.Status()
if err != nil {
return baseInfo, err
}
if baseInfo.Status == "not running" {
return baseInfo, err
}
baseInfo.Version, err = client.Version()
if err != nil {
return baseInfo, err
}
return baseInfo, nil
}
@@ -76,7 +67,6 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
datas []fireClient.FireInfo
backDatas []fireClient.FireInfo
)
client, err := firewall.NewFirewallClient()
if err != nil {
return 0, nil, err
@@ -110,61 +100,14 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
datas = addrs
}
}
var datasFilterStatus []fireClient.FireInfo
if len(req.Status) != 0 {
for _, data := range datas {
portItem, _ := strconv.Atoi(data.Port)
if req.Status == "free" && !common.ScanPortWithProto(portItem, data.Protocol) {
datasFilterStatus = append(datasFilterStatus, data)
}
if req.Status == "used" && common.ScanPortWithProto(portItem, data.Protocol) {
datasFilterStatus = append(datasFilterStatus, data)
}
}
} else {
datasFilterStatus = datas
}
var datasFilterStrategy []fireClient.FireInfo
if len(req.Strategy) != 0 {
for _, data := range datasFilterStatus {
if req.Strategy == data.Strategy {
datasFilterStrategy = append(datasFilterStrategy, data)
}
}
} else {
datasFilterStrategy = datasFilterStatus
}
total, start, end := len(datasFilterStrategy), (req.Page-1)*req.PageSize, req.Page*req.PageSize
total, start, end := len(datas), (req.Page-1)*req.PageSize, req.Page*req.PageSize
if start > total {
backDatas = make([]fireClient.FireInfo, 0)
} else {
if end >= total {
end = total
}
backDatas = datasFilterStrategy[start:end]
}
datasFromDB, _ := hostRepo.ListFirewallRecord()
for i := 0; i < len(backDatas); i++ {
for _, des := range datasFromDB {
if req.Type != des.Type {
continue
}
if backDatas[i].Port == des.Port &&
req.Type == "port" &&
backDatas[i].Protocol == des.Protocol &&
backDatas[i].Strategy == des.Strategy &&
backDatas[i].Address == des.Address {
backDatas[i].Description = des.Description
break
}
if req.Type == "address" && backDatas[i].Strategy == des.Strategy && backDatas[i].Address == des.Address {
backDatas[i].Description = des.Description
break
}
}
backDatas = datas[start:end]
}
if req.Type == "port" {
@@ -184,7 +127,6 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
}
}
}
go u.cleanUnUsedData(client)
return int64(total), backDatas, nil
}
@@ -225,27 +167,16 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
return err
}
protos := strings.Split(req.Protocol, "/")
itemAddress := strings.Split(strings.TrimSuffix(req.Address, ","), ",")
var wg sync.WaitGroup
if client.Name() == "ufw" {
if len(req.Address) == 0 {
req.Address = "Anywhere"
}
if strings.Contains(req.Port, ",") || strings.Contains(req.Port, "-") {
for _, proto := range protos {
for _, addr := range itemAddress {
if len(addr) == 0 {
addr = "Anywhere"
}
req.Address = addr
req.Port = strings.ReplaceAll(req.Port, "-", ":")
req.Protocol = proto
wg.Add(1)
go func(req dto.PortRuleOperate) {
defer wg.Done()
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
_ = u.addPortRecord(req)
}(req)
req.Port = strings.ReplaceAll(req.Port, "-", ":")
req.Protocol = proto
if err := u.operatePort(client, req); err != nil {
return err
}
}
return nil
@@ -253,19 +184,8 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
if req.Protocol == "tcp/udp" {
req.Protocol = ""
}
for _, addr := range itemAddress {
if len(addr) == 0 {
addr = "Anywhere"
}
req.Address = addr
wg.Add(1)
go func(req dto.PortRuleOperate) {
defer wg.Done()
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
_ = u.addPortRecord(req)
}(req)
if err := u.operatePort(client, req); err != nil {
return err
}
return nil
}
@@ -273,17 +193,9 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
itemPorts := req.Port
for _, proto := range protos {
if strings.Contains(req.Port, "-") {
for _, addr := range itemAddress {
req.Protocol = proto
req.Address = addr
wg.Add(1)
go func(req dto.PortRuleOperate) {
defer wg.Done()
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
_ = u.addPortRecord(req)
}(req)
req.Protocol = proto
if err := u.operatePort(client, req); err != nil {
return err
}
} else {
ports := strings.Split(itemPorts, ",")
@@ -291,28 +203,15 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
if len(port) == 0 {
continue
}
for _, addr := range itemAddress {
req.Address = addr
req.Port = port
req.Protocol = proto
wg.Add(1)
go func(req dto.PortRuleOperate) {
defer wg.Done()
if err := u.operatePort(client, req); err != nil {
global.LOG.Errorf("%s port %s/%s failed (strategy: %s, address: %s), err: %v", req.Operation, req.Port, req.Protocol, req.Strategy, req.Address, err)
}
_ = u.addPortRecord(req)
}(req)
req.Port = port
req.Protocol = proto
if err := u.operatePort(client, req); err != nil {
return err
}
}
}
}
wg.Wait()
if reload {
return client.Reload()
}
return nil
return client.Reload()
}
func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate, reload bool) error {
@@ -326,22 +225,15 @@ func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate, reload boo
return err
}
var wg sync.WaitGroup
addressList := strings.Split(req.Address, ",")
for _, addr := range addressList {
if len(addr) == 0 {
continue
}
fireInfo.Address = addr
wg.Add(1)
go func(req dto.AddrRuleOperate) {
defer wg.Done()
if err := client.RichRules(fireInfo, req.Operation); err != nil {
global.LOG.Errorf("%s address %s failed (strategy: %s), err: %v", req.Operation, req.Address, req.Strategy, err)
}
req.Address = fireInfo.Address
_ = u.addAddressRecord(req)
}(req)
if err := client.RichRules(fireInfo, req.Operation); err != nil {
return err
}
}
if reload {
return client.Reload()
@@ -377,38 +269,24 @@ func (u *FirewallService) UpdateAddrRule(req dto.AddrRuleUpdate) error {
return client.Reload()
}
func (u *FirewallService) UpdateDescription(req dto.UpdateFirewallDescription) error {
var firewall model.Firewall
if err := copier.Copy(&firewall, &req); err != nil {
return errors.WithMessage(constant.ErrStructTransform, err.Error())
}
return hostRepo.SaveFirewallRecord(&firewall)
}
func (u *FirewallService) BatchOperateRule(req dto.BatchRuleOperate) error {
client, err := firewall.NewFirewallClient()
if err != nil {
return err
}
var wgBatch sync.WaitGroup
if req.Type == "port" {
for _, rule := range req.Rules {
wgBatch.Add(1)
go func(item dto.PortRuleOperate) {
defer wgBatch.Done()
_ = u.OperatePortRule(item, false)
}(rule)
if err := u.OperatePortRule(rule, false); err != nil {
return err
}
}
wgBatch.Wait()
return client.Reload()
}
for _, rule := range req.Rules {
itemRule := dto.AddrRuleOperate{Operation: rule.Operation, Address: rule.Address, Strategy: rule.Strategy}
wgBatch.Add(1)
go func(item dto.AddrRuleOperate) {
defer wgBatch.Done()
_ = u.OperateAddressRule(item, false)
}(itemRule)
if err := u.OperateAddressRule(itemRule, false); err != nil {
return err
}
}
return client.Reload()
}
@@ -438,7 +316,7 @@ func (u *FirewallService) operatePort(client firewall.FirewallClient, req dto.Po
}
if client.Name() == "ufw" {
if len(fireInfo.Address) != 0 && !strings.EqualFold(fireInfo.Address, "Anywhere") {
if len(fireInfo.Address) != 0 && fireInfo.Address != "Anywhere" {
return client.RichRules(fireInfo, req.Operation)
}
return client.Port(fireInfo, req.Operation)
@@ -478,29 +356,6 @@ func (u *FirewallService) loadPortByApp() []portOfApp {
return datas
}
func (u *FirewallService) cleanUnUsedData(client firewall.FirewallClient) {
list, _ := client.ListPort()
addressList, _ := client.ListAddress()
list = append(list, addressList...)
if len(list) == 0 {
return
}
records, _ := hostRepo.ListFirewallRecord()
if len(records) == 0 {
return
}
for _, item := range list {
for i := 0; i < len(records); i++ {
if records[i].Port == item.Port && records[i].Protocol == item.Protocol && records[i].Strategy == item.Strategy && records[i].Address == item.Address {
records = append(records[:i], records[i+1:]...)
}
}
}
for _, record := range records {
_ = hostRepo.DeleteFirewallRecordByID(record.ID)
}
}
func (u *FirewallService) pingStatus() string {
if _, err := os.Stat("/etc/sysctl.conf"); err != nil {
return constant.StatusNone
@@ -579,30 +434,3 @@ func (u *FirewallService) addPortsBeforeStart(client firewall.FirewallClient) er
return client.Reload()
}
func (u *FirewallService) addPortRecord(req dto.PortRuleOperate) error {
if req.Operation == "remove" {
return hostRepo.DeleteFirewallRecord("port", req.Port, req.Protocol, req.Address, req.Strategy)
}
return hostRepo.SaveFirewallRecord(&model.Firewall{
Type: "port",
Port: req.Port,
Protocol: req.Protocol,
Address: req.Address,
Strategy: req.Strategy,
Description: req.Description,
})
}
func (u *FirewallService) addAddressRecord(req dto.AddrRuleOperate) error {
if req.Operation == "remove" {
return hostRepo.DeleteFirewallRecord("address", "", "", req.Address, req.Strategy)
}
return hostRepo.SaveFirewallRecord(&model.Firewall{
Type: "address",
Address: req.Address,
Strategy: req.Strategy,
Description: req.Description,
})
}
+59 -32
View File
@@ -3,6 +3,14 @@ package service
import (
"bytes"
"fmt"
"os/exec"
"os/user"
"path"
"strconv"
"strings"
"sync"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
"github.com/1Panel-dev/1Panel/backend/buserr"
@@ -14,11 +22,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
"github.com/pkg/errors"
"gopkg.in/ini.v1"
"os/exec"
"os/user"
"path"
"strconv"
"strings"
)
type HostToolService struct{}
@@ -31,6 +34,7 @@ type IHostToolService interface {
GetToolLog(req request.HostToolLogReq) (string, error)
OperateSupervisorProcess(req request.SupervisorProcessConfig) error
GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error)
LoadProcessStatus() ([]response.ProcessStatus, error)
OperateSupervisorProcessFile(req request.SupervisorProcessFileReq) (string, error)
}
@@ -373,6 +377,56 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
return nil
}
func (h *HostToolService) LoadProcessStatus() ([]response.ProcessStatus, error) {
var res []response.ProcessStatus
statusLines, _ := cmd.Exec("supervisorctl status")
if len(statusLines) == 0 {
return res, nil
}
lines := strings.Split(statusLines, "\n")
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) > 1 {
res = append(res, response.ProcessStatus{Name: fields[0]})
}
}
var wg sync.WaitGroup
wg.Add(len(res))
for i := 0; i < len(res); i++ {
go func(index int) {
for t := 0; t < 3; t++ {
status, err := cmd.ExecWithTimeOut(fmt.Sprintf("supervisorctl status %s", res[index].Name), 2*time.Second)
if err != nil {
time.Sleep(2 * time.Second)
continue
}
fields := strings.Fields(status)
if len(fields) < 5 {
time.Sleep(2 * time.Second)
continue
}
res[index].Name = fields[0]
res[index].Status = fields[1]
if fields[1] != "RUNNING" {
res[index].Msg = strings.Join(fields[2:], " ")
break
}
res[index].PID = strings.TrimSuffix(fields[3], ",")
res[index].Uptime = fields[5]
break
}
if len(res[index].Status) == 0 {
res[index].Status = "FATAL"
res[index].Msg = "Timeout for getting process status"
}
wg.Done()
}(i)
}
wg.Wait()
return res, nil
}
func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error) {
var (
result []response.SupervisorProcessConfig
@@ -409,7 +463,6 @@ func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorPro
if numprocs, _ := section.GetKey("numprocs"); numprocs != nil {
config.Numprocs = numprocs.Value()
}
_ = getProcessStatus(&config)
result = append(result, config)
}
}
@@ -537,29 +590,3 @@ func getProcessName(name, numprocs string) []string {
}
return processNames
}
func getProcessStatus(config *response.SupervisorProcessConfig) error {
var (
processNames = []string{"status"}
)
processNames = append(processNames, getProcessName(config.Name, config.Numprocs)...)
output, _ := exec.Command("supervisorctl", processNames...).Output()
lines := strings.Split(string(output), "\n")
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) >= 5 {
status := response.ProcessStatus{
Name: fields[0],
Status: fields[1],
}
if fields[1] == "RUNNING" {
status.PID = strings.TrimSuffix(fields[3], ",")
status.Uptime = fields[5]
} else {
status.Msg = strings.Join(fields[2:], " ")
}
config.Status = append(config.Status, status)
}
}
return nil
}
+1 -10
View File
@@ -1,7 +1,6 @@
package service
import (
"fmt"
"io"
"net/http"
"os"
@@ -62,15 +61,7 @@ func (n NginxService) UpdateConfigByScope(req request.NginxConfigUpdate) error {
}
func (n NginxService) GetStatus() (response.NginxStatus, error) {
httpPort, _, err := getAppInstallPort(constant.AppOpenresty)
if err != nil {
return response.NginxStatus{}, err
}
url := "http://127.0.0.1/nginx_status"
if httpPort != 80 {
url = fmt.Sprintf("http://127.0.0.1:%v/nginx_status", httpPort)
}
res, err := http.Get(url)
res, err := http.Get("http://127.0.0.1/nginx_status")
if err != nil {
return response.NginxStatus{}, err
}
@@ -2,43 +2,40 @@ package service
import (
"context"
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"github.com/1Panel-dev/1Panel/backend/utils/mysql"
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
)
type DatabaseService struct{}
type RemoteDBService struct{}
type IDatabaseService interface {
Get(name string) (dto.DatabaseInfo, error)
SearchWithPage(search dto.DatabaseSearch) (int64, interface{}, error)
CheckDatabase(req dto.DatabaseCreate) bool
Create(req dto.DatabaseCreate) error
Update(req dto.DatabaseUpdate) error
type IRemoteDBService interface {
Get(name string) (dto.RemoteDBInfo, error)
SearchWithPage(search dto.RemoteDBSearch) (int64, interface{}, error)
CheckeRemoteDB(req dto.RemoteDBCreate) bool
Create(req dto.RemoteDBCreate) error
Update(req dto.RemoteDBUpdate) error
Delete(id uint) error
List(dbType string) ([]dto.DatabaseOption, error)
List(dbType string) ([]dto.RemoteDBOption, error)
}
func NewIDatabaseService() IDatabaseService {
return &DatabaseService{}
func NewIRemoteDBService() IRemoteDBService {
return &RemoteDBService{}
}
func (u *DatabaseService) SearchWithPage(search dto.DatabaseSearch) (int64, interface{}, error) {
total, dbs, err := databaseRepo.Page(search.Page, search.PageSize,
databaseRepo.WithTypeList(search.Type),
func (u *RemoteDBService) SearchWithPage(search dto.RemoteDBSearch) (int64, interface{}, error) {
total, dbs, err := remoteDBRepo.Page(search.Page, search.PageSize,
commonRepo.WithByType(search.Type),
commonRepo.WithLikeName(search.Info),
databaseRepo.WithoutByFrom("local"),
remoteDBRepo.WithoutByFrom("local"),
)
var datas []dto.DatabaseInfo
var datas []dto.RemoteDBInfo
for _, db := range dbs {
var item dto.DatabaseInfo
var item dto.RemoteDBInfo
if err := copier.Copy(&item, &db); err != nil {
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
@@ -47,9 +44,9 @@ func (u *DatabaseService) SearchWithPage(search dto.DatabaseSearch) (int64, inte
return total, datas, err
}
func (u *DatabaseService) Get(name string) (dto.DatabaseInfo, error) {
var data dto.DatabaseInfo
remote, err := databaseRepo.Get(commonRepo.WithByName(name))
func (u *RemoteDBService) Get(name string) (dto.RemoteDBInfo, error) {
var data dto.RemoteDBInfo
remote, err := remoteDBRepo.Get(commonRepo.WithByName(name))
if err != nil {
return data, err
}
@@ -59,21 +56,20 @@ func (u *DatabaseService) Get(name string) (dto.DatabaseInfo, error) {
return data, nil
}
func (u *DatabaseService) List(dbType string) ([]dto.DatabaseOption, error) {
dbs, err := databaseRepo.GetList(databaseRepo.WithTypeList(dbType))
var datas []dto.DatabaseOption
func (u *RemoteDBService) List(dbType string) ([]dto.RemoteDBOption, error) {
dbs, err := remoteDBRepo.GetList(commonRepo.WithByType(dbType))
var datas []dto.RemoteDBOption
for _, db := range dbs {
var item dto.DatabaseOption
var item dto.RemoteDBOption
if err := copier.Copy(&item, &db); err != nil {
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
item.Database = db.Name
datas = append(datas, item)
}
return datas, err
}
func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
func (u *RemoteDBService) CheckeRemoteDB(req dto.RemoteDBCreate) bool {
if _, err := mysql.NewMysqlClient(client.DBInfo{
From: "remote",
Address: req.Address,
@@ -87,12 +83,9 @@ func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
return true
}
func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
db, _ := databaseRepo.Get(commonRepo.WithByName(req.Name))
func (u *RemoteDBService) Create(req dto.RemoteDBCreate) error {
db, _ := remoteDBRepo.Get(commonRepo.WithByName(req.Name))
if db.ID != 0 {
if db.From == "local" {
return buserr.New(constant.ErrLocalExist)
}
return constant.ErrRecordExist
}
if _, err := mysql.NewMysqlClient(client.DBInfo{
@@ -108,29 +101,29 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
if err := copier.Copy(&db, &req); err != nil {
return errors.WithMessage(constant.ErrStructTransform, err.Error())
}
if err := databaseRepo.Create(context.Background(), &db); err != nil {
if err := remoteDBRepo.Create(&db); err != nil {
return err
}
return nil
}
func (u *DatabaseService) Delete(id uint) error {
db, _ := databaseRepo.Get(commonRepo.WithByID(id))
func (u *RemoteDBService) Delete(id uint) error {
db, _ := remoteDBRepo.Get(commonRepo.WithByID(id))
if db.ID == 0 {
return constant.ErrRecordNotFound
}
if err := databaseRepo.Delete(context.Background(), commonRepo.WithByID(id)); err != nil {
if err := remoteDBRepo.Delete(commonRepo.WithByID(id)); err != nil {
return err
}
if db.From != "local" {
if err := mysqlRepo.Delete(context.Background(), mysqlRepo.WithByMysqlName(db.Name)); err != nil {
if err := mysqlRepo.Delete(context.Background(), remoteDBRepo.WithByFrom(db.Name)); err != nil {
return err
}
}
return nil
}
func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
func (u *RemoteDBService) Update(req dto.RemoteDBUpdate) error {
if _, err := mysql.NewMysqlClient(client.DBInfo{
From: "remote",
Address: req.Address,
@@ -142,18 +135,12 @@ func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
return err
}
pass, err := encrypt.StringEncrypt(req.Password)
if err != nil {
return fmt.Errorf("decrypt database password failed, err: %v", err)
}
upMap := make(map[string]interface{})
upMap["type"] = req.Type
upMap["version"] = req.Version
upMap["address"] = req.Address
upMap["port"] = req.Port
upMap["username"] = req.Username
upMap["password"] = pass
upMap["password"] = req.Password
upMap["description"] = req.Description
return databaseRepo.Update(req.ID, upMap)
return remoteDBRepo.Update(req.ID, upMap)
}
+2 -2
View File
@@ -113,7 +113,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (err error) {
if err = runtimeRepo.Create(context.Background(), runtime); err != nil {
return
}
go buildRuntime(runtime, "", false)
go buildRuntime(runtime, "")
return
}
@@ -272,6 +272,6 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
if err != nil {
return err
}
go buildRuntime(runtime, imageID, req.Rebuild)
go buildRuntime(runtime, imageID)
return nil
}
+1 -25
View File
@@ -3,7 +3,6 @@ package service
import (
"bytes"
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
@@ -18,7 +17,7 @@ import (
"strings"
)
func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
func buildRuntime(runtime *model.Runtime, oldImageID string) {
runtimePath := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
composePath := path.Join(runtimePath, "docker-compose.yml")
logPath := path.Join(runtimePath, "build.log")
@@ -62,29 +61,6 @@ func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
global.LOG.Errorf("delete imageID [%s] error %v", oldImageID, err)
}
}
if rebuild && runtime.ID > 0 {
websites, _ := websiteRepo.GetBy(websiteRepo.WithRuntimeID(runtime.ID))
if len(websites) > 0 {
installService := NewIAppInstalledService()
installMap := make(map[uint]string)
for _, website := range websites {
if website.AppInstallID > 0 {
installMap[website.AppInstallID] = website.PrimaryDomain
}
}
for installID, domain := range installMap {
go func(installID uint, domain string) {
global.LOG.Infof("rebuild php runtime [%s] domain [%s]", runtime.Name, domain)
if err := installService.Operate(request.AppInstalledOperate{
InstallId: installID,
Operate: constant.Rebuild,
}); err != nil {
global.LOG.Errorf("rebuild php runtime [%s] domain [%s] error %v", runtime.Name, domain, err)
}
}(installID, domain)
}
}
}
}
_ = runtimeRepo.Save(runtime)
}
-7
View File
@@ -103,12 +103,6 @@ func (u *SettingService) Update(key, value string) error {
if err := ntp.UpdateSystemTimeZone(value); err != nil {
return err
}
case "AppStoreLastModified":
exist, _ := settingRepo.Get(settingRepo.WithByKey("AppStoreLastModified"))
if exist.ID == 0 {
_ = settingRepo.Create("AppStoreLastModified", value)
return nil
}
}
if err := settingRepo.Update(key, value); err != nil {
@@ -134,7 +128,6 @@ func (u *SettingService) Update(key, value string) error {
}
case "UserName", "Password":
_ = global.SESSION.Clean()
}
return nil
+199 -231
View File
@@ -9,7 +9,6 @@ import (
"regexp"
"strconv"
"strings"
"sync"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@@ -17,7 +16,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/jinzhu/copier"
@@ -36,12 +34,8 @@ type ISnapshotService interface {
SnapshotImport(req dto.SnapshotImport) error
Delete(req dto.BatchDeleteReq) error
LoadSnapShotStatus(id uint) (*dto.SnapshotStatus, error)
UpdateDescription(req dto.UpdateDescription) error
readFromJson(path string) (SnapshotJson, error)
HandleSnapshot(isCronjob bool, req dto.SnapshotCreate, timeNow string) (string, string, error)
}
func NewISnapshotService() ISnapshotService {
@@ -72,14 +66,13 @@ func (u *SnapshotService) SnapshotImport(req dto.SnapshotImport) error {
}
}
for _, snap := range req.Names {
shortName := strings.TrimPrefix(snap, "snapshot_")
nameItems := strings.Split(shortName, "_")
if !strings.HasPrefix(shortName, "1panel_v") || !strings.HasSuffix(shortName, ".tar.gz") || len(nameItems) != 3 {
return fmt.Errorf("incorrect snapshot name format of %s", shortName)
nameItems := strings.Split(snap, "_")
if !strings.HasPrefix(snap, "1panel_v") || !strings.HasSuffix(snap, ".tar.gz") || len(nameItems) != 3 {
return fmt.Errorf("incorrect snapshot name format of %s", snap)
}
formatTime, err := time.Parse("20060102150405", strings.ReplaceAll(nameItems[2], ".tar.gz", ""))
if err != nil {
return fmt.Errorf("incorrect snapshot name format of %s", shortName)
return fmt.Errorf("incorrect snapshot name format of %s", snap)
}
if strings.HasSuffix(snap, ".tar.gz") {
snap = strings.ReplaceAll(snap, ".tar.gz", "")
@@ -106,18 +99,6 @@ func (u *SnapshotService) UpdateDescription(req dto.UpdateDescription) error {
return snapshotRepo.Update(req.ID, map[string]interface{}{"description": req.Description})
}
func (u *SnapshotService) LoadSnapShotStatus(id uint) (*dto.SnapshotStatus, error) {
var data dto.SnapshotStatus
status, err := snapshotRepo.GetStatus(id)
if err != nil {
return nil, err
}
if err := copier.Copy(&data, &status); err != nil {
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
}
return &data, nil
}
type SnapshotJson struct {
OldBaseDir string `json:"oldBaseDir"`
OldDockerDataDir string `json:"oldDockerDataDir"`
@@ -132,9 +113,112 @@ type SnapshotJson struct {
}
func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
if _, _, err := u.HandleSnapshot(false, req, time.Now().Format("20060102150405")); err != nil {
global.LOG.Info("start to create snapshot now")
localDir, err := loadLocalDir()
if err != nil {
return err
}
backup, err := backupRepo.Get(commonRepo.WithByType(req.From))
if err != nil {
return err
}
backupAccount, err := NewIBackupService().NewClient(&backup)
if err != nil {
return err
}
timeNow := time.Now().Format("20060102150405")
versionItem, _ := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
rootDir := path.Join(localDir, fmt.Sprintf("system/1panel_%s_%s", versionItem.Value, timeNow))
backupPanelDir := fmt.Sprintf("%s/1panel", rootDir)
_ = os.MkdirAll(backupPanelDir, os.ModePerm)
backupDockerDir := fmt.Sprintf("%s/docker", rootDir)
_ = os.MkdirAll(backupDockerDir, os.ModePerm)
_ = settingRepo.Update("SystemStatus", "Snapshoting")
snap := model.Snapshot{
Name: fmt.Sprintf("1panel_%s_%s", versionItem.Value, timeNow),
Description: req.Description,
From: req.From,
Version: versionItem.Value,
Status: constant.StatusSuccess,
}
_ = snapshotRepo.Create(&snap)
go func() {
_ = global.Cron.Stop()
defer func() {
global.Cron.Start()
_ = os.RemoveAll(rootDir)
}()
fileOp := files.NewFileOp()
snapJson := SnapshotJson{
BaseDir: global.CONF.System.BaseDir,
BackupDataDir: localDir,
}
if err := u.handleDockerDatasWithSave(fileOp, "snapshot", "", backupDockerDir); err != nil {
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
return
}
if err := u.handleDaemonJson(fileOp, "snapshot", "", backupDockerDir); err != nil {
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
return
}
if err := u.handlePanelBinary(fileOp, "snapshot", "", backupPanelDir+"/1panel"); err != nil {
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
return
}
if err := u.handlePanelctlBinary(fileOp, "snapshot", "", backupPanelDir+"/1pctl"); err != nil {
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
return
}
if err := u.handlePanelService(fileOp, "snapshot", "", backupPanelDir+"/1panel.service"); err != nil {
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
return
}
if err := u.handleBackupDatas(fileOp, "snapshot", localDir, backupPanelDir); err != nil {
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
return
}
dataDir := path.Join(global.CONF.System.BaseDir, "1panel")
if err := u.handlePanelDatas(snap.ID, fileOp, "snapshot", dataDir, backupPanelDir, localDir, snapJson.DockerDataDir); err != nil {
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
return
}
_, _ = cmd.Exec("systemctl restart docker")
snapJson.PanelDataDir = dataDir
if err := u.saveJson(snapJson, rootDir); err != nil {
updateSnapshotStatus(snap.ID, constant.StatusFailed, fmt.Sprintf("save snapshot json failed, err: %v", err))
return
}
if err := handleTar(rootDir, path.Join(localDir, "system"), fmt.Sprintf("1panel_%s_%s.tar.gz", versionItem.Value, timeNow), ""); err != nil {
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
return
}
_ = settingRepo.Update("SystemStatus", "Free")
global.LOG.Infof("start to upload snapshot to %s, please wait", backup.Type)
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusUploading})
localPath := path.Join(localDir, fmt.Sprintf("system/1panel_%s_%s.tar.gz", versionItem.Value, timeNow))
itemBackupPath := strings.TrimPrefix(backup.BackupPath, "/")
itemBackupPath = strings.TrimSuffix(itemBackupPath, "/")
if ok, err := backupAccount.Upload(localPath, fmt.Sprintf("%s/system_snapshot/1panel_%s_%s.tar.gz", itemBackupPath, versionItem.Value, timeNow)); err != nil || !ok {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
global.LOG.Errorf("upload snapshot to %s failed, err: %v", backup.Type, err)
return
}
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusSuccess})
_ = os.RemoveAll(path.Join(localDir, fmt.Sprintf("system/1panel_%s_%s.tar.gz", versionItem.Value, timeNow)))
global.LOG.Infof("upload snapshot to %s success", backup.Type)
}()
return nil
}
@@ -469,135 +553,14 @@ func (u *SnapshotService) readFromJson(path string) (SnapshotJson, error) {
return snap, nil
}
func (u *SnapshotService) HandleSnapshot(isCronjob bool, req dto.SnapshotCreate, timeNow string) (string, string, error) {
localDir, err := loadLocalDir()
if err != nil {
return "", "", err
}
var (
rootDir string
snap model.Snapshot
snapStatus model.SnapshotStatus
)
if req.ID == 0 {
versionItem, _ := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
name := fmt.Sprintf("1panel_%s_%s", versionItem.Value, timeNow)
if isCronjob {
name = fmt.Sprintf("snapshot_1panel_%s_%s", versionItem.Value, timeNow)
}
rootDir = path.Join(localDir, "system", name)
snap = model.Snapshot{
Name: name,
Description: req.Description,
From: req.From,
Version: versionItem.Value,
Status: constant.StatusWaiting,
}
_ = snapshotRepo.Create(&snap)
snapStatus.SnapID = snap.ID
_ = snapshotRepo.CreateStatus(&snapStatus)
} else {
snap, err = snapshotRepo.Get(commonRepo.WithByID(req.ID))
if err != nil {
return "", "", err
}
snapStatus, _ = snapshotRepo.GetStatus(snap.ID)
if snapStatus.ID == 0 {
snapStatus.SnapID = snap.ID
_ = snapshotRepo.CreateStatus(&snapStatus)
}
rootDir = path.Join(localDir, fmt.Sprintf("system/%s", snap.Name))
}
var wg sync.WaitGroup
itemHelper := snapHelper{SnapID: snap.ID, Status: &snapStatus, Wg: &wg, FileOp: files.NewFileOp(), Ctx: context.Background()}
backupPanelDir := path.Join(rootDir, "1panel")
_ = os.MkdirAll(backupPanelDir, os.ModePerm)
backupDockerDir := path.Join(rootDir, "docker")
_ = os.MkdirAll(backupDockerDir, os.ModePerm)
jsonItem := SnapshotJson{
BaseDir: global.CONF.System.BaseDir,
BackupDataDir: localDir,
PanelDataDir: path.Join(global.CONF.System.BaseDir, "1panel"),
}
if snapStatus.PanelInfo != constant.StatusDone {
wg.Add(1)
go snapJson(itemHelper, jsonItem, rootDir)
}
if snapStatus.Panel != constant.StatusDone {
wg.Add(1)
go snapPanel(itemHelper, backupPanelDir)
}
if snapStatus.DaemonJson != constant.StatusDone {
wg.Add(1)
go snapDaemonJson(itemHelper, backupDockerDir)
}
if snapStatus.AppData != constant.StatusDone {
wg.Add(1)
go snapAppData(itemHelper, backupDockerDir)
}
if snapStatus.BackupData != constant.StatusDone {
wg.Add(1)
go snapBackup(itemHelper, localDir, backupPanelDir)
}
if snapStatus.PanelData != constant.StatusDone {
wg.Add(1)
go snapPanelData(itemHelper, localDir, backupPanelDir)
}
if !isCronjob {
go func() {
wg.Wait()
if !checkIsAllDone(snap.ID) {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
return
}
snapCompress(itemHelper, rootDir)
if snapStatus.Compress != constant.StatusDone {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
return
}
snapUpload(itemHelper, req.From, fmt.Sprintf("%s.tar.gz", rootDir))
if snapStatus.Upload != constant.StatusDone {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
return
}
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusSuccess})
}()
return "", "", nil
}
wg.Wait()
if !checkIsAllDone(snap.ID) {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
return loadLogByStatus(snapStatus), snap.Name, fmt.Errorf("snapshot %s backup failed", snap.Name)
}
snapCompress(itemHelper, rootDir)
if snapStatus.Compress != constant.StatusDone {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
return loadLogByStatus(snapStatus), snap.Name, fmt.Errorf("snapshot %s compress failed", snap.Name)
}
snapUpload(itemHelper, req.From, fmt.Sprintf("%s.tar.gz", rootDir))
if snapStatus.Upload != constant.StatusDone {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
return loadLogByStatus(snapStatus), snap.Name, fmt.Errorf("snapshot %s upload failed", snap.Name)
}
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusSuccess})
return loadLogByStatus(snapStatus), snap.Name, nil
}
func (u *SnapshotService) handleDockerDatas(fileOp files.FileOp, operation string, source, target string) error {
switch operation {
case "snapshot":
if err := handleSnapTar(source, target, "docker_data.tar.gz", ""); err != nil {
if err := u.handleTar(source, target, "docker_data.tar.gz", ""); err != nil {
return fmt.Errorf("backup docker data failed, err: %v", err)
}
case "recover":
if err := handleSnapTar(target, u.OriginalPath, "docker_data.tar.gz", ""); err != nil {
if err := u.handleTar(target, u.OriginalPath, "docker_data.tar.gz", ""); err != nil {
return fmt.Errorf("backup docker data failed, err: %v", err)
}
if err := u.handleUnTar(source+"/docker/docker_data.tar.gz", target); err != nil {
@@ -618,6 +581,31 @@ func (u *SnapshotService) handleDockerDatas(fileOp files.FileOp, operation strin
func (u *SnapshotService) handleDockerDatasWithSave(fileOp files.FileOp, operation, source, target string) error {
switch operation {
case "snapshot":
appInstalls, err := appInstallRepo.ListBy()
if err != nil {
return err
}
imageRegex := regexp.MustCompile(`image:\s*(.*)`)
var imageSaveList []string
existStr, _ := cmd.Exec("docker images | awk '{print $1\":\"$2}' | grep -v REPOSITORY:TAG")
existImages := strings.Split(existStr, "\n")
duplicateMap := make(map[string]bool)
for _, app := range appInstalls {
matches := imageRegex.FindAllStringSubmatch(app.DockerCompose, -1)
for _, match := range matches {
for _, existImage := range existImages {
if match[1] == existImage && !duplicateMap[match[1]] {
imageSaveList = append(imageSaveList, match[1])
duplicateMap[match[1]] = true
}
}
}
}
std, err := cmd.Execf("docker save %s | gzip -c > %s", strings.Join(imageSaveList, " "), path.Join(target, "docker_image.tar"))
if err != nil {
return errors.New(std)
}
case "recover":
if err := u.handleDockerDatasWithSave(fileOp, "snapshot", "", u.OriginalPath); err != nil {
return fmt.Errorf("backup docker data failed, err: %v", err)
@@ -675,7 +663,7 @@ func (u *SnapshotService) handlePanelBinary(fileOp files.FileOp, operation strin
if _, err := os.Stat(panelPath); err != nil {
return fmt.Errorf("1panel binary is not found in %s, err: %v", panelPath, err)
} else {
if err := cpBinary([]string{panelPath}, target); err != nil {
if err := cpBinary(panelPath, target); err != nil {
return fmt.Errorf("backup 1panel binary failed, err: %v", err)
}
}
@@ -684,7 +672,7 @@ func (u *SnapshotService) handlePanelBinary(fileOp files.FileOp, operation strin
if _, err := os.Stat(source); err != nil {
return fmt.Errorf("1panel binary is not found in snapshot, err: %v", err)
} else {
if err := cpBinary([]string{source}, "/usr/local/bin/1panel"); err != nil {
if err := cpBinary(source, "/usr/local/bin/1panel"); err != nil {
return fmt.Errorf("recover 1panel binary failed, err: %v", err)
}
}
@@ -699,7 +687,7 @@ func (u *SnapshotService) handlePanelctlBinary(fileOp files.FileOp, operation st
if _, err := os.Stat(panelctlPath); err != nil {
return fmt.Errorf("1pctl binary is not found in %s, err: %v", panelctlPath, err)
} else {
if err := cpBinary([]string{panelctlPath}, target); err != nil {
if err := cpBinary(panelctlPath, target); err != nil {
return fmt.Errorf("backup 1pctl binary failed, err: %v", err)
}
}
@@ -708,7 +696,7 @@ func (u *SnapshotService) handlePanelctlBinary(fileOp files.FileOp, operation st
if _, err := os.Stat(source); err != nil {
return fmt.Errorf("1pctl binary is not found in snapshot, err: %v", err)
} else {
if err := cpBinary([]string{source}, "/usr/local/bin/1pctl"); err != nil {
if err := cpBinary(source, "/usr/local/bin/1pctl"); err != nil {
return fmt.Errorf("recover 1pctl binary failed, err: %v", err)
}
}
@@ -723,7 +711,7 @@ func (u *SnapshotService) handlePanelService(fileOp files.FileOp, operation stri
if _, err := os.Stat(panelServicePath); err != nil {
return fmt.Errorf("1panel service is not found in %s, err: %v", panelServicePath, err)
} else {
if err := cpBinary([]string{panelServicePath}, target); err != nil {
if err := cpBinary(panelServicePath, target); err != nil {
return fmt.Errorf("backup 1panel service failed, err: %v", err)
}
}
@@ -732,7 +720,7 @@ func (u *SnapshotService) handlePanelService(fileOp files.FileOp, operation stri
if _, err := os.Stat(source); err != nil {
return fmt.Errorf("1panel service is not found in snapshot, err: %v", err)
} else {
if err := cpBinary([]string{source}, "/etc/systemd/system/1panel.service"); err != nil {
if err := cpBinary(source, "/etc/systemd/system/1panel.service"); err != nil {
return fmt.Errorf("recover 1panel service failed, err: %v", err)
}
}
@@ -743,8 +731,12 @@ func (u *SnapshotService) handlePanelService(fileOp files.FileOp, operation stri
func (u *SnapshotService) handleBackupDatas(fileOp files.FileOp, operation string, source, target string) error {
switch operation {
case "snapshot":
if err := u.handleTar(source, target, "1panel_backup.tar.gz", "./system;"); err != nil {
return fmt.Errorf("backup panel local backup dir data failed, err: %v", err)
}
case "recover":
if err := handleSnapTar(target, u.OriginalPath, "1panel_backup.tar.gz", "./system;"); err != nil {
if err := u.handleTar(target, u.OriginalPath, "1panel_backup.tar.gz", "./system;"); err != nil {
return fmt.Errorf("restore original local backup dir data failed, err: %v", err)
}
if err := u.handleUnTar(source+"/1panel/1panel_backup.tar.gz", target); err != nil {
@@ -766,7 +758,7 @@ func (u *SnapshotService) handleBackupDatas(fileOp files.FileOp, operation strin
func (u *SnapshotService) handlePanelDatas(snapID uint, fileOp files.FileOp, operation string, source, target, backupDir, dockerDir string) error {
switch operation {
case "snapshot":
exclusionRules := "./tmp;./log;./cache;"
exclusionRules := "./tmp;./log;./cache;./db/1Panel.db-*;"
if strings.Contains(backupDir, source) {
exclusionRules += ("." + strings.ReplaceAll(backupDir, source, "") + ";")
}
@@ -774,11 +766,11 @@ func (u *SnapshotService) handlePanelDatas(snapID uint, fileOp files.FileOp, ope
exclusionRules += ("." + strings.ReplaceAll(dockerDir, source, "") + ";")
}
if err := handleSnapTar(source, target, "1panel_data.tar.gz", exclusionRules); err != nil {
if err := u.handleTar(source, target, "1panel_data.tar.gz", exclusionRules); err != nil {
return fmt.Errorf("backup panel data failed, err: %v", err)
}
case "recover":
exclusionRules := "./tmp;./log;./cache;"
exclusionRules := "./tmp;./log;./cache;./db/1Panel.db-*;"
if strings.Contains(backupDir, target) {
exclusionRules += ("." + strings.ReplaceAll(backupDir, target, "") + ";")
}
@@ -787,7 +779,7 @@ func (u *SnapshotService) handlePanelDatas(snapID uint, fileOp files.FileOp, ope
}
_ = snapshotRepo.Update(snapID, map[string]interface{}{"recover_status": ""})
if err := handleSnapTar(target, u.OriginalPath, "1panel_data.tar.gz", exclusionRules); err != nil {
if err := u.handleTar(target, u.OriginalPath, "1panel_data.tar.gz", exclusionRules); err != nil {
return fmt.Errorf("restore original panel data failed, err: %v", err)
}
_ = snapshotRepo.Update(snapID, map[string]interface{}{"recover_status": constant.StatusWaiting})
@@ -829,13 +821,10 @@ func (u *SnapshotService) Delete(req dto.BatchDeleteReq) error {
return err
}
for _, snap := range backups {
itemFile := path.Join(localDir, "system", snap.Name)
_ = os.RemoveAll(itemFile)
itemTarFile := path.Join(global.CONF.System.TmpDir, "system", snap.Name+".tar.gz")
_ = os.Remove(itemTarFile)
_ = snapshotRepo.DeleteStatus(snap.ID)
itemFile := path.Join(localDir, fmt.Sprintf("system/%s/%s.tar.gz", snap.Name, snap.Name))
if _, err := os.Stat(itemFile); err == nil {
_ = os.Remove(itemFile)
}
}
if err := snapshotRepo.Delete(commonRepo.WithIdsIn(req.Ids)); err != nil {
return err
@@ -844,6 +833,18 @@ func (u *SnapshotService) Delete(req dto.BatchDeleteReq) error {
return nil
}
func updateSnapshotStatus(id uint, status string, message string) {
if status != constant.StatusSuccess {
global.LOG.Errorf("snapshot failed, err: %s", message)
}
if err := snapshotRepo.Update(id, map[string]interface{}{
"status": status,
"message": message,
}); err != nil {
global.LOG.Errorf("update snap snapshot status failed, err: %v", err)
}
_ = settingRepo.Update("SystemStatus", "Free")
}
func updateRecoverStatus(id uint, interruptStep, status string, message string) {
if status != constant.StatusSuccess {
global.LOG.Errorf("recover failed, err: %s", message)
@@ -883,8 +884,8 @@ func updateRollbackStatus(id uint, status string, message string) {
}
}
func cpBinary(src []string, dst string) error {
stderr, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", strings.Join(src, " "), dst))
func cpBinary(src, dst string) error {
stderr, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", src, dst))
if err != nil {
return errors.New(stderr)
}
@@ -938,6 +939,35 @@ func (u *SnapshotService) updateLiveRestore(enabled bool) error {
return nil
}
func (u *SnapshotService) handleTar(sourceDir, targetDir, name, exclusionRules string) error {
if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(targetDir, os.ModePerm); err != nil {
return err
}
}
exStr := ""
excludes := strings.Split(exclusionRules, ";")
for _, exclude := range excludes {
if len(exclude) == 0 {
continue
}
exStr += " --exclude "
exStr += exclude
}
commands := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
global.LOG.Debug(commands)
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
if err != nil {
if len(stdout) != 0 {
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
return fmt.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
}
}
return nil
}
func (u *SnapshotService) handleUnTar(sourceDir, targetDir string) error {
if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(targetDir, os.ModePerm); err != nil {
@@ -958,35 +988,14 @@ func (u *SnapshotService) handleUnTar(sourceDir, targetDir string) error {
}
func rebuildAllAppInstall() error {
global.LOG.Debug("start to rebuild all app")
appInstalls, err := appInstallRepo.ListBy()
if err != nil {
global.LOG.Errorf("get all app installed for rebuild failed, err: %v", err)
return err
}
var wg sync.WaitGroup
for i := 0; i < len(appInstalls); i++ {
wg.Add(1)
appInstalls[i].Status = constant.Rebuilding
_ = appInstallRepo.Save(context.Background(), &appInstalls[i])
go func(app model.AppInstall) {
defer wg.Done()
dockerComposePath := app.GetComposePath()
out, err := compose.Down(dockerComposePath)
if err != nil {
_ = handleErr(app, err, out)
return
}
out, err = compose.Up(dockerComposePath)
if err != nil {
_ = handleErr(app, err, out)
return
}
app.Status = constant.Running
_ = appInstallRepo.Save(context.Background(), &app)
}(appInstalls[i])
for _, install := range appInstalls {
_ = rebuildApp(install)
}
wg.Wait()
return nil
}
@@ -1026,44 +1035,3 @@ func min(a, b int) int {
}
return b
}
func checkIsAllDone(snapID uint) bool {
status, err := snapshotRepo.GetStatus(snapID)
if err != nil {
return false
}
if status.Panel != constant.StatusDone {
return false
}
if status.PanelInfo != constant.StatusDone {
return false
}
if status.DaemonJson != constant.StatusDone {
return false
}
if status.AppData != constant.StatusDone {
return false
}
if status.PanelData != constant.StatusDone {
return false
}
if status.BackupData != constant.StatusDone {
return false
}
return true
}
func loadLogByStatus(status model.SnapshotStatus) string {
logs := ""
logs += fmt.Sprintf("Write 1Panel basic information: %s \n", status.PanelInfo)
logs += fmt.Sprintf("Backup 1Panel system files: %s \n", status.Panel)
logs += fmt.Sprintf("Backup Docker configuration file: %s \n", status.DaemonJson)
logs += fmt.Sprintf("Backup installed apps from 1Panel: %s \n", status.AppData)
logs += fmt.Sprintf("Backup 1Panel data directory: %s \n", status.PanelData)
logs += fmt.Sprintf("Backup local backup directory for 1Panel: %s \n", status.BackupData)
logs += fmt.Sprintf("Create snapshot file: %s \n", status.Compress)
logs += fmt.Sprintf("Snapshot size: %s \n", status.Size)
logs += fmt.Sprintf("Upload snapshot file: %s \n", status.Upload)
return logs
}
-236
View File
@@ -1,236 +0,0 @@
package service
import (
"context"
"encoding/json"
"fmt"
"os"
"path"
"regexp"
"strings"
"sync"
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
)
type snapHelper struct {
SnapID uint
Status *model.SnapshotStatus
Ctx context.Context
FileOp files.FileOp
Wg *sync.WaitGroup
}
func snapJson(snap snapHelper, snapJson SnapshotJson, targetDir string) {
defer snap.Wg.Done()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel_info": constant.Running})
status := constant.StatusDone
remarkInfo, _ := json.MarshalIndent(snapJson, "", "\t")
if err := os.WriteFile(fmt.Sprintf("%s/snapshot.json", targetDir), remarkInfo, 0640); err != nil {
status = err.Error()
}
snap.Status.PanelInfo = status
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel_info": status})
}
func snapPanel(snap snapHelper, targetDir string) {
defer snap.Wg.Done()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel": constant.Running})
status := constant.StatusDone
if err := cpBinary([]string{"/usr/local/bin/1panel", "/usr/local/bin/1pctl", "/etc/systemd/system/1panel.service"}, targetDir); err != nil {
status = err.Error()
}
snap.Status.Panel = status
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel": status})
}
func snapDaemonJson(snap snapHelper, targetDir string) {
defer snap.Wg.Done()
status := constant.StatusDone
if !snap.FileOp.Stat("/etc/docker/daemon.json") {
snap.Status.DaemonJson = status
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"daemon_json": status})
return
}
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"daemon_json": constant.Running})
if err := cpBinary([]string{"/etc/docker/daemon.json"}, path.Join(targetDir, "daemon.json")); err != nil {
status = err.Error()
}
snap.Status.DaemonJson = status
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"daemon_json": status})
}
func snapAppData(snap snapHelper, targetDir string) {
defer snap.Wg.Done()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"app_data": constant.Running})
appInstalls, err := appInstallRepo.ListBy()
if err != nil {
snap.Status.AppData = err.Error()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"app_data": err.Error()})
return
}
runtimes, err := runtimeRepo.List()
if err != nil {
snap.Status.AppData = err.Error()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"app_data": err.Error()})
return
}
imageRegex := regexp.MustCompile(`image:\s*(.*)`)
var imageSaveList []string
existStr, _ := cmd.Exec("docker images | awk '{print $1\":\"$2}' | grep -v REPOSITORY:TAG")
existImages := strings.Split(existStr, "\n")
duplicateMap := make(map[string]bool)
for _, app := range appInstalls {
matches := imageRegex.FindAllStringSubmatch(app.DockerCompose, -1)
for _, match := range matches {
for _, existImage := range existImages {
if match[1] == existImage && !duplicateMap[match[1]] {
imageSaveList = append(imageSaveList, match[1])
duplicateMap[match[1]] = true
}
}
}
}
for _, rumtime := range runtimes {
for _, existImage := range existImages {
if rumtime.Image == existImage && !duplicateMap[rumtime.Image] {
imageSaveList = append(imageSaveList, rumtime.Image)
duplicateMap[rumtime.Image] = true
}
}
}
global.LOG.Debugf("docker save %s | gzip -c > %s", strings.Join(imageSaveList, " "), path.Join(targetDir, "docker_image.tar"))
std, err := cmd.Execf("docker save %s | gzip -c > %s", strings.Join(imageSaveList, " "), path.Join(targetDir, "docker_image.tar"))
if err != nil {
snap.Status.AppData = err.Error()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"app_data": std})
return
}
snap.Status.AppData = constant.StatusDone
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"app_data": constant.StatusDone})
}
func snapBackup(snap snapHelper, localDir, targetDir string) {
defer snap.Wg.Done()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"backup_data": constant.Running})
status := constant.StatusDone
if err := handleSnapTar(localDir, targetDir, "1panel_backup.tar.gz", "./system;"); err != nil {
status = err.Error()
}
snap.Status.BackupData = status
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"backup_data": status})
}
func snapPanelData(snap snapHelper, localDir, targetDir string) {
defer snap.Wg.Done()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel_data": constant.Running})
status := constant.StatusDone
dataDir := path.Join(global.CONF.System.BaseDir, "1panel")
exclusionRules := "./tmp;./log;./cache;"
if strings.Contains(localDir, dataDir) {
exclusionRules += ("." + strings.ReplaceAll(localDir, dataDir, "") + ";")
}
_ = snapshotRepo.Update(snap.SnapID, map[string]interface{}{"status": "OnSaveData"})
if err := handleSnapTar(dataDir, targetDir, "1panel_data.tar.gz", exclusionRules); err != nil {
status = err.Error()
}
_ = snapshotRepo.Update(snap.SnapID, map[string]interface{}{"status": constant.StatusWaiting})
snap.Status.PanelData = status
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel_data": status})
}
func snapCompress(snap snapHelper, rootDir string) {
defer func() {
global.LOG.Debugf("remove snapshot file %s", rootDir)
_ = os.RemoveAll(rootDir)
}()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": constant.StatusRunning})
tmpDir := path.Join(global.CONF.System.TmpDir, "system")
fileName := fmt.Sprintf("%s.tar.gz", path.Base(rootDir))
if err := snap.FileOp.Compress([]string{rootDir}, tmpDir, fileName, files.TarGz); err != nil {
snap.Status.Compress = err.Error()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": err.Error()})
return
}
stat, err := os.Stat(path.Join(tmpDir, fileName))
if err != nil {
snap.Status.Compress = err.Error()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": err.Error()})
return
}
size := common.LoadSizeUnit(float64(stat.Size()))
global.LOG.Debugf("compress successful! size of file: %s", size)
snap.Status.Compress = constant.StatusDone
snap.Status.Size = size
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": constant.StatusDone, "size": size})
}
func snapUpload(snap snapHelper, account string, file string) {
source := path.Join(global.CONF.System.TmpDir, "system", path.Base(file))
defer func() {
global.LOG.Debugf("remove snapshot file %s", source)
_ = os.Remove(source)
}()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": constant.StatusUploading})
backup, err := backupRepo.Get(commonRepo.WithByType(account))
if err != nil {
snap.Status.Upload = err.Error()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": err.Error()})
return
}
client, err := NewIBackupService().NewClient(&backup)
if err != nil {
snap.Status.Upload = err.Error()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": err.Error()})
return
}
target := path.Join(strings.TrimPrefix(backup.BackupPath, "/"), "system_snapshot", path.Base(file))
global.LOG.Debugf("start upload snapshot to %s, dir: %s", backup.Type, target)
if _, err := client.Upload(source, target); err != nil {
snap.Status.Upload = err.Error()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": err.Error()})
return
}
snap.Status.Upload = constant.StatusDone
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": constant.StatusDone})
}
func handleSnapTar(sourceDir, targetDir, name, exclusionRules string) error {
if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(targetDir, os.ModePerm); err != nil {
return err
}
}
exStr := ""
excludes := strings.Split(exclusionRules, ";")
for _, exclude := range excludes {
if len(exclude) == 0 {
continue
}
exStr += " --exclude "
exStr += exclude
}
commands := fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
global.LOG.Debug(commands)
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
if err != nil {
if len(stdout) != 0 {
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
return fmt.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
}
}
return nil
}
+12 -39
View File
@@ -18,8 +18,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/qqwry"
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
"github.com/pkg/errors"
)
const sshPath = "/etc/ssh/sshd_config"
@@ -53,20 +51,19 @@ func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
PermitRootLogin: "yes",
UseDNS: "yes",
}
serviceName, err := loadServiceName()
sudo := cmd.SudoHandleCmd()
stdout, err := cmd.Execf("%s systemctl status sshd", sudo)
if err != nil {
data.Message = stdout
data.Status = constant.StatusDisable
data.Message = err.Error()
} else {
active, err := systemctl.IsActive(serviceName)
if !active {
data.Status = constant.StatusDisable
data.Message = err.Error()
} else {
}
stdLines := strings.Split(stdout, "\n")
for _, stdline := range stdLines {
if strings.Contains(stdline, "active (running)") {
data.Status = constant.StatusEnable
break
}
}
sshConf, err := os.ReadFile(sshPath)
if err != nil {
data.Message = err.Error()
@@ -98,14 +95,10 @@ func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
func (u *SSHService) OperateSSH(operation string) error {
if operation == "start" || operation == "stop" || operation == "restart" {
serviceName, err := loadServiceName()
if err != nil {
return err
}
sudo := cmd.SudoHandleCmd()
stdout, err := cmd.Execf("%s systemctl %s %s", sudo, operation, serviceName)
stdout, err := cmd.Execf("%s systemctl %s sshd", sudo, operation)
if err != nil {
return fmt.Errorf("%s %s failed, stdout: %s, err: %v", operation, serviceName, stdout, err)
return fmt.Errorf("%s sshd failed, stdout: %s, err: %v", operation, stdout, err)
}
return nil
}
@@ -113,11 +106,6 @@ func (u *SSHService) OperateSSH(operation string) error {
}
func (u *SSHService) Update(key, value string) error {
serviceName, err := loadServiceName()
if err != nil {
return err
}
sshConf, err := os.ReadFile(sshPath)
if err != nil {
return err
@@ -142,17 +130,11 @@ func (u *SSHService) Update(key, value string) error {
_, _ = cmd.Execf("%s semanage port -a -t ssh_port_t -p tcp %s", sudo, value)
}
}
_, _ = cmd.Execf("%s systemctl restart %s", sudo, serviceName)
_, _ = cmd.Execf("%s systemctl restart sshd", sudo)
return nil
}
func (u *SSHService) UpdateByFile(value string) error {
serviceName, err := loadServiceName()
if err != nil {
return err
}
file, err := os.OpenFile(sshPath, os.O_WRONLY|os.O_TRUNC, 0666)
if err != nil {
return err
@@ -162,7 +144,7 @@ func (u *SSHService) UpdateByFile(value string) error {
return err
}
sudo := cmd.SudoHandleCmd()
_, _ = cmd.Execf("%s systemctl restart %s", sudo, serviceName)
_, _ = cmd.Execf("%s systemctl restart sshd", sudo)
return nil
}
@@ -476,12 +458,3 @@ func handleGunzip(path string) error {
}
return nil
}
func loadServiceName() (string, error) {
if exist, _ := systemctl.IsExist("sshd"); exist {
return "sshd", nil
} else if exist, _ := systemctl.IsExist("ssh"); exist {
return "ssh", nil
}
return "", errors.New("The ssh or sshd service is unavailable")
}
+7 -11
View File
@@ -104,10 +104,6 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
fileName := fmt.Sprintf("1panel-%s-%s-%s.tar.gz", req.Version, "linux", itemArch)
_ = settingRepo.Update("SystemStatus", "Upgrading")
go func() {
_ = global.Cron.Stop()
defer func() {
global.Cron.Start()
}()
if err := fileOp.DownloadFile(downloadPath+"/"+fileName, rootDir+"/"+fileName); err != nil {
global.LOG.Errorf("download service file failed, err: %v", err)
_ = settingRepo.Update("SystemStatus", "Free")
@@ -131,13 +127,13 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
}
global.LOG.Info("backup original data successful, now start to upgrade!")
if err := cpBinary([]string{tmpDir + "/1panel"}, "/usr/local/bin/1panel"); err != nil {
if err := cpBinary(tmpDir+"/1panel", "/usr/local/bin/1panel"); err != nil {
u.handleRollback(fileOp, originalDir, 1)
global.LOG.Errorf("upgrade 1panel failed, err: %v", err)
return
}
if err := cpBinary([]string{tmpDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
if err := cpBinary(tmpDir+"/1pctl", "/usr/local/bin/1pctl"); err != nil {
u.handleRollback(fileOp, originalDir, 2)
global.LOG.Errorf("upgrade 1pctl failed, err: %v", err)
return
@@ -148,7 +144,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
return
}
if err := cpBinary([]string{tmpDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
if err := cpBinary(tmpDir+"/1panel.service", "/etc/systemd/system/1panel.service"); err != nil {
u.handleRollback(fileOp, originalDir, 3)
global.LOG.Errorf("upgrade 1panel.service failed, err: %v", err)
return
@@ -183,22 +179,22 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e
func (u *UpgradeService) handleRollback(fileOp files.FileOp, originalDir string, errStep int) {
dbPath := global.CONF.System.DbPath + "/1Panel.db"
_ = settingRepo.Update("SystemStatus", "Free")
if err := cpBinary([]string{originalDir + "/1Panel.db"}, dbPath); err != nil {
if err := cpBinary(originalDir+"/1Panel.db", dbPath); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
if err := cpBinary([]string{originalDir + "/1panel"}, "/usr/local/bin/1panel"); err != nil {
if err := cpBinary(originalDir+"/1panel", "/usr/local/bin/1panel"); err != nil {
global.LOG.Errorf("rollback 1pctl failed, err: %v", err)
}
if errStep == 1 {
return
}
if err := cpBinary([]string{originalDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
if err := cpBinary(originalDir+"/1pctl", "/usr/local/bin/1pctl"); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
if errStep == 2 {
return
}
if err := cpBinary([]string{originalDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
if err := cpBinary(originalDir+"/1panel.service", "/etc/systemd/system/1panel.service"); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
}
+22 -90
View File
@@ -15,18 +15,14 @@ import (
"regexp"
"strconv"
"strings"
"syscall"
"time"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/spf13/afero"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/1Panel-dev/1Panel/backend/utils/env"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
@@ -84,7 +80,6 @@ type IWebsiteService interface {
GetRewriteConfig(req request.NginxRewriteReq) (*response.NginxRewriteRes, error)
UpdateRewriteConfig(req request.NginxRewriteUpdate) error
LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*response.WebsiteDirConfig, error)
UpdateSiteDir(req request.WebsiteUpdateDir) error
UpdateSitePermission(req request.WebsiteUpdateDirPermission) error
OperateProxy(req request.WebsiteProxyConfig) (err error)
@@ -180,11 +175,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
if exist, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithDomain(create.PrimaryDomain)); len(exist) > 0 {
return buserr.New(constant.ErrDomainIsExist)
}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
defaultHttpPort := nginxInstall.HttpPort
defaultDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
website := &model.Website{
@@ -301,13 +291,13 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
}
var domains []model.WebsiteDomain
domains = append(domains, model.WebsiteDomain{Domain: website.PrimaryDomain, Port: defaultHttpPort})
domains = append(domains, model.WebsiteDomain{Domain: website.PrimaryDomain, Port: 80})
otherDomainArray := strings.Split(create.OtherDomains, "\n")
for _, domain := range otherDomainArray {
if domain == "" {
continue
}
domainModel, err := getDomain(domain, defaultHttpPort)
domainModel, err := getDomain(domain)
if err != nil {
return err
}
@@ -455,20 +445,11 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
ports []int
domains []string
)
httpPort, _, err := getAppInstallPort(constant.AppOpenresty)
if err != nil {
return domainModel, err
}
if existDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithPort(create.Port)); len(existDomains) == 0 {
if existAppInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithPort(create.Port)); !reflect.DeepEqual(existAppInstall, model.AppInstall{}) {
return domainModel, buserr.WithMap(constant.ErrPortInOtherApp, map[string]interface{}{"port": create.Port, "apps": existAppInstall.App.Name}, nil)
}
if create.Port != 80 {
if common.ScanPort(create.Port) {
return domainModel, buserr.WithDetail(constant.ErrPortInUsed, create.Port, nil)
}
}
website, err := websiteRepo.GetFirst(commonRepo.WithByID(create.WebsiteID))
if err != nil {
return domainModel, err
@@ -485,7 +466,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
Port: create.Port,
WebsiteID: create.WebsiteID,
}
if create.Port != httpPort {
if create.Port != 80 {
go func() {
_ = OperateFirewallPort(nil, []int{create.Port})
}()
@@ -671,12 +652,7 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
if !req.Enable {
website.Protocol = constant.ProtocolHTTP
website.WebsiteSSLID = 0
_, httpsPort, err := getAppInstallPort(constant.AppOpenresty)
if err != nil {
return nil, err
}
httpsPortStr := strconv.Itoa(httpsPort)
if err := deleteListenAndServerName(website, []string{httpsPortStr, "[::]:" + httpsPortStr}, []string{}); err != nil {
if err := deleteListenAndServerName(website, []string{"443", "[::]:443"}, []string{}); err != nil {
return nil, err
}
nginxParams := getNginxParamsFromStaticFile(dto.SSL, nil)
@@ -817,7 +793,7 @@ func (w WebsiteService) PreInstallCheck(req request.WebsiteInstallCheckReq) ([]r
checkIds = append(req.InstallIds, appInstall.ID)
}
for _, id := range checkIds {
if err := syncByID(id); err != nil {
if err := syncById(id); err != nil {
return nil, err
}
}
@@ -936,12 +912,19 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi
}
}
filePath := path.Join(sitePath, "log", req.LogType)
lines, end, err := files.ReadFileByLine(filePath, req.Page, req.PageSize)
fileInfo, err := os.Stat(filePath)
if err != nil {
return nil, err
}
res.End = end
res.Content = strings.Join(lines, "\n")
if fileInfo.Size() > 20<<20 {
return nil, buserr.New(constant.ErrFileToLarge)
}
fileInfo.Size()
content, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
res.Content = string(content)
return res, nil
case constant.DisableLog:
key := "access_log"
@@ -1024,17 +1007,12 @@ func (w WebsiteService) ChangeDefaultServer(id uint) error {
if err != nil {
return err
}
httpPort, httpsPort, err := getAppInstallPort(constant.AppOpenresty)
if err != nil {
return err
}
var changeParams []dto.NginxParam
for _, param := range params {
paramLen := len(param.Params)
bind := param.Params[0]
var newParam []string
if bind == strconv.Itoa(httpPort) || bind == strconv.Itoa(httpsPort) || bind == "[::]:"+strconv.Itoa(httpPort) || bind == "[::]:"+strconv.Itoa(httpsPort) {
if bind == "80" || bind == "443" || bind == "[::]:80" || bind == "[::]:443" {
if param.Params[paramLen-1] == components.DefaultServer {
newParam = param.Params
} else {
@@ -1394,7 +1372,7 @@ func (w WebsiteService) UpdateSiteDir(req request.WebsiteUpdateDir) error {
runDir := req.SiteDir
siteDir := path.Join("/www/sites", website.Alias, "index")
if req.SiteDir != "/" {
siteDir = fmt.Sprintf("%s%s", siteDir, req.SiteDir)
siteDir = fmt.Sprintf("%s/%s", siteDir, req.SiteDir)
}
if err := updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "root", Params: []string{siteDir}}}, &website); err != nil {
return err
@@ -1413,6 +1391,9 @@ func (w WebsiteService) UpdateSitePermission(req request.WebsiteUpdateDirPermiss
return err
}
absoluteIndexPath := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "index")
if website.SiteDir != "/" {
absoluteIndexPath = path.Join(absoluteIndexPath, website.SiteDir)
}
chownCmd := fmt.Sprintf("chown -R %s:%s %s", req.User, req.Group, absoluteIndexPath)
if cmd.HasNoPasswordSudo() {
chownCmd = fmt.Sprintf("sudo %s", chownCmd)
@@ -2320,52 +2301,3 @@ func (w WebsiteService) UpdateWafFile(req request.WebsiteWafFileUpdate) (err err
rulePath := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "waf", "rules", fmt.Sprintf("%s.json", req.Type))
return files.NewFileOp().WriteFile(rulePath, strings.NewReader(req.Content), 0755)
}
func (w WebsiteService) LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*response.WebsiteDirConfig, error) {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
return nil, err
}
res := &response.WebsiteDirConfig{}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return nil, err
}
absoluteIndexPath := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "index")
var appFs = afero.NewOsFs()
info, err := appFs.Stat(absoluteIndexPath)
if err != nil {
return nil, err
}
res.User = strconv.FormatUint(uint64(info.Sys().(*syscall.Stat_t).Uid), 10)
res.UserGroup = strconv.FormatUint(uint64(info.Sys().(*syscall.Stat_t).Gid), 10)
indexFiles, err := os.ReadDir(absoluteIndexPath)
if err != nil {
return nil, err
}
res.Dirs = []string{"/"}
for _, file := range indexFiles {
if !file.IsDir() {
continue
}
res.Dirs = append(res.Dirs, fmt.Sprintf("/%s", file.Name()))
fileInfo, _ := file.Info()
if fileInfo.Sys().(*syscall.Stat_t).Uid != 1000 || fileInfo.Sys().(*syscall.Stat_t).Gid != 1000 {
res.Msg = i18n.GetMsgByKey("ErrPathPermission")
}
childFiles, _ := os.ReadDir(absoluteIndexPath + "/" + file.Name())
for _, childFile := range childFiles {
if !childFile.IsDir() {
continue
}
childInfo, _ := childFile.Info()
if childInfo.Sys().(*syscall.Stat_t).Uid != 1000 || childInfo.Sys().(*syscall.Stat_t).Gid != 1000 {
res.Msg = i18n.GetMsgByKey("ErrPathPermission")
}
res.Dirs = append(res.Dirs, fmt.Sprintf("/%s/%s", file.Name(), childFile.Name()))
}
}
return res, nil
}
+1 -1
View File
@@ -115,7 +115,7 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
if err != nil {
return request.WebsiteSSLCreate{}, err
}
if err := client.UseHTTP(path.Join(appInstall.GetPath(), "root")); err != nil {
if err := client.UseHTTP(path.Join(constant.AppInstallDir, constant.AppOpenresty, appInstall.Name, "root")); err != nil {
return res, err
}
websiteSSL.AutoRenew = create.AutoRenew
+11 -18
View File
@@ -23,12 +23,12 @@ import (
"gorm.io/gorm"
)
func getDomain(domainStr string, defaultPort int) (model.WebsiteDomain, error) {
func getDomain(domainStr string) (model.WebsiteDomain, error) {
domain := model.WebsiteDomain{}
domainArray := strings.Split(domainStr, ":")
if len(domainArray) == 1 {
domain.Domain = domainArray[0]
domain.Port = defaultPort
domain.Port = 80
return domain, nil
}
if len(domainArray) > 1 {
@@ -186,7 +186,6 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
return errors.New("nginx config is not valid")
}
server := servers[0]
server.DeleteListen("80")
var serverNames []string
for _, domain := range domains {
serverNames = append(serverNames, domain.Domain)
@@ -379,33 +378,27 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
}
config := nginxFull.SiteConfig.Config
server := config.FindServers()[0]
httpPort := strconv.Itoa(nginxFull.Install.HttpPort)
httpsPort := strconv.Itoa(nginxFull.Install.HttpsPort)
httpPortIPV6 := "[::]:" + httpPort
httpsPortIPV6 := "[::]:" + httpsPort
server.UpdateListen(httpsPort, website.DefaultServer, "ssl", "http2")
server.UpdateListen("443", website.DefaultServer, "ssl", "http2")
if website.IPV6 {
server.UpdateListen(httpsPortIPV6, website.DefaultServer, "ssl", "http2")
server.UpdateListen("[::]:443", website.DefaultServer, "ssl", "http2")
}
switch req.HttpConfig {
case constant.HTTPSOnly:
server.RemoveListenByBind(httpPort)
server.RemoveListenByBind(httpPortIPV6)
server.RemoveListenByBind("80")
server.RemoveListenByBind("[::]:80")
server.RemoveDirective("if", []string{"($scheme"})
case constant.HTTPToHTTPS:
server.UpdateListen(httpPort, website.DefaultServer)
server.UpdateListen("80", website.DefaultServer)
if website.IPV6 {
server.UpdateListen(httpPortIPV6, website.DefaultServer)
server.UpdateListen("[::]:80", website.DefaultServer)
}
server.AddHTTP2HTTPS()
case constant.HTTPAlso:
server.UpdateListen(httpPort, website.DefaultServer)
server.UpdateListen("80", website.DefaultServer)
server.RemoveDirective("if", []string{"($scheme"})
if website.IPV6 {
server.UpdateListen(httpPortIPV6, website.DefaultServer)
server.UpdateListen("[::]:80", website.DefaultServer)
}
}
@@ -633,7 +626,7 @@ func checkIsLinkApp(website model.Website) bool {
}
func chownRootDir(path string) error {
_, err := cmd.ExecWithTimeOut(fmt.Sprintf(`chown -R 1000:1000 "%s"`, path), 1*time.Second)
_, err := cmd.ExecWithTimeOut(fmt.Sprintf("chown -R 1000:1000 %s", path), 1*time.Second)
if err != nil {
return err
}
-2
View File
@@ -12,7 +12,6 @@ const (
Upgrading = "Upgrading"
UpgradeErr = "UpgradeErr"
PullErr = "PullErr"
Rebuilding = "Rebuilding"
ContainerPrefix = "1Panel-"
@@ -21,7 +20,6 @@ const (
AppOpenresty = "openresty"
AppMysql = "mysql"
AppMariaDB = "mariadb"
AppRedis = "redis"
AppResourceLocal = "local"
-3
View File
@@ -96,8 +96,6 @@ var (
ErrUserIsExist = "ErrUserIsExist"
ErrDatabaseIsExist = "ErrDatabaseIsExist"
ErrExecTimeOut = "ErrExecTimeOut"
ErrRemoteExist = "ErrRemoteExist"
ErrLocalExist = "ErrLocalExist"
)
// redis
@@ -124,5 +122,4 @@ var (
var (
ErrBackupInUsed = "ErrBackupInUsed"
ErrOSSConn = "ErrOSSConn"
ErrEntrance = "ErrEntrance"
)
-1
View File
@@ -2,7 +2,6 @@ package constant
const (
StatusRunning = "Running"
StatusDone = "Done"
StatusStoped = "Stoped"
StatusWaiting = "Waiting"
StatusSuccess = "Success"
+1 -5
View File
@@ -20,7 +20,7 @@ ErrPortInUsed: "{{ .detail }} port already in use"
ErrAppLimit: "App exceeds install limit"
ErrAppRequired: "{{ .detail }} app is required"
ErrNotInstall: "App not installed"
ErrPortInOtherApp: "{{ .port }} port already in use by app {{ .apps }}"
ErrPortInOtherApp: "{{ .port }} port already in use by {{ .apps }}"
ErrDbUserNotValid: "Stock database, username and password do not match!"
ErrDockerComposeNotValid: "docker-compose file format error!"
ErrUpdateBuWebsite: 'The application was updated successfully, but the modification of the website configuration file failed, please check the configuration!'
@@ -66,7 +66,6 @@ ErrGroupIsUsed: 'The group is in use and cannot be deleted'
ErrBackupMatch: 'the backup file does not match the current partial data of the website: {{ .detail}}"'
ErrBackupExist: 'the backup file corresponds to a portion of the original data that does not exist: {{ .detail}}"'
ErrPHPResource: 'The local runtime does not support switching!'
ErrPathPermission: 'A folder with non-1000:1000 permissions was detected in the index directory, which may cause Access denied errors when accessing the website.'
#ssl
ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed"
@@ -82,8 +81,6 @@ ErrSSLCertificateFormat: 'Certificate file format error, please use pem format'
ErrUserIsExist: "The current user already exists. Please enter a new user"
ErrDatabaseIsExist: "The current database already exists. Please enter a new database"
ErrExecTimeOut: "SQL execution timed out, please check the database"
ErrRemoteExist: "The remote database already exists with that name, please modify it and try again"
ErrLocalExist: "The local database already exists with that name, please modify it and try again"
#redis
ErrTypeOfRedis: "The recovery file type does not match the current persistence mode. Modify the file type and try again"
@@ -103,7 +100,6 @@ ErrDelWithWebsite: "The operating environment has been associated with a website
#setting
ErrBackupInUsed: "The backup account is already being used in a cronjob and cannot be deleted."
ErrOSSConn: "Unable to successfully request the latest version. Please check if the server can connect to the external network environment."
ErrEntrance: "Security entrance information error. Please check and try again!"
#tool
ErrConfigNotFound: "Configuration file does not exist"
+1 -5
View File
@@ -20,7 +20,7 @@ ErrPortInUsed: "{{ .detail }} 端口已被佔用!"
ErrAppLimit: "應用超出安裝數量限制"
ErrAppRequired: "請先安裝 {{ .detail }} 應用"
ErrNotInstall: "應用未安裝"
ErrPortInOtherApp: "{{ .port }} 端口已被應用 {{ .apps }} 佔用!"
ErrPortInOtherApp: "{{ .port }} 端口已被 {{ .apps }}佔用!"
ErrDbUserNotValid: "儲存資料庫,用戶名密碼不匹配!"
ErrDockerComposeNotValid: "docker-compose 文件格式錯誤"
ErrUpdateBuWebsite: '應用更新成功,但是網站配置文件修改失敗,請檢查配置!'
@@ -66,7 +66,6 @@ ErrGroupIsUsed: '分組正在使用中,無法刪除'
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}"'
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}"'
ErrPHPResource: '本地運行環境不支持切換!'
ErrPathPermission: 'index 目錄下檢測到非 1000:1000 權限文件夾,可能導致網站訪問 Access denied 錯誤'
#ssl
ErrSSLCannotDelete: "證書正在被網站使用,無法刪除"
@@ -82,8 +81,6 @@ ErrSSLCertificateFormat: '證書文件格式錯誤,請使用 pem 格式'
ErrUserIsExist: "當前用戶已存在,請重新輸入"
ErrDatabaseIsExist: "當前資料庫已存在,請重新輸入"
ErrExecTimeOut: "SQL 執行超時,請檢查數據庫"
ErrRemoteExist: "遠程數據庫已存在該名稱,請修改後重試"
ErrLocalExist: "本地數據庫已存在該名稱,請修改後重試"
#redis
ErrTypeOfRedis: "恢復文件類型與當前持久化方式不符,請修改後重試"
@@ -103,7 +100,6 @@ ErrDelWithWebsite: "運行環境已經關聯網站,無法刪除"
#setting
ErrBackupInUsed: "該備份帳號已在計劃任務中使用,無法刪除"
ErrOSSConn: "無法成功請求最新版本,請檢查伺服器是否能夠連接到外部網絡環境。"
ErrEntrance: "安全入口信息錯誤,請檢查後重試!"
#tool
ErrConfigNotFound: "配置文件不存在"
+1 -5
View File
@@ -20,7 +20,7 @@ ErrPortInUsed: "{{ .detail }} 端口已被占用!"
ErrAppLimit: "应用超出安装数量限制"
ErrAppRequired: "请先安装 {{ .detail }} 应用"
ErrNotInstall: "应用未安装"
ErrPortInOtherApp: "{{ .port }} 端口已被应用 {{ .apps }} 占用!"
ErrPortInOtherApp: "{{ .port }} 端口已被 {{ .apps }}占用!"
ErrDbUserNotValid: "存量数据库,用户名密码不匹配!"
ErrDockerComposeNotValid: "docker-compose 文件格式错误"
ErrUpdateBuWebsite: '应用更新成功,但是网站配置文件修改失败,请检查配置!'
@@ -66,7 +66,6 @@ ErrGroupIsUsed: '分组正在使用中,无法删除'
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}"'
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}"'
ErrPHPResource: '本地运行环境不支持切换!'
ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误'
#ssl
ErrSSLCannotDelete: "证书正在被网站使用,无法删除"
@@ -82,8 +81,6 @@ ErrSSLCertificateFormat: '证书文件格式错误,请使用 pem 格式'
ErrUserIsExist: "当前用户已存在,请重新输入"
ErrDatabaseIsExist: "当前数据库已存在,请重新输入"
ErrExecTimeOut: "SQL 执行超时,请检查数据库"
ErrRemoteExist: "远程数据库已存在该名称,请修改后重试"
ErrLocalExist: "本地数据库已存在该名称,请修改后重试"
#redis
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
@@ -103,7 +100,6 @@ ErrDelWithWebsite: "运行环境已经关联网站,无法删除"
#setting
ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除"
ErrOSSConn: "无法成功请求最新版本,请检查服务器是否能够连接到外部网络环境。"
ErrEntrance: "安全入口信息错误,请检查后重试!"
#tool
ErrConfigNotFound: "配置文件不存在"
+5 -48
View File
@@ -4,7 +4,6 @@ import (
"encoding/base64"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
@@ -18,6 +17,11 @@ func Init() {
global.LOG.Errorf("load service port from setting failed, err: %v", err)
}
global.CONF.System.Port = portSetting.Value
encryptSetting, err := settingRepo.Get(settingRepo.WithByKey("EncryptKey"))
if err != nil {
global.LOG.Errorf("load service encrypt key from setting failed, err: %v", err)
}
global.CONF.System.EncryptKey = encryptSetting.Value
sslSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
if err != nil {
global.LOG.Errorf("load service ssl from setting failed, err: %v", err)
@@ -59,51 +63,4 @@ func Init() {
sudo := cmd.SudoHandleCmd()
_, _ = cmd.Execf("%s sed -i '/CHANGE_USER_INFO=true/d' /usr/local/bin/1pctl", sudo)
}
handleSnapStatus()
}
func handleSnapStatus() {
snapRepo := repo.NewISnapshotRepo()
snaps, _ := snapRepo.GetList()
for _, snap := range snaps {
if snap.Status == "OnSaveData" {
_ = snapRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusSuccess})
}
if snap.Status == constant.StatusWaiting {
_ = snapRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed, "message": "the task was interrupted due to the restart of the 1panel service"})
}
}
status, _ := snapRepo.GetStatusList()
for _, statu := range status {
updates := make(map[string]interface{})
if statu.Panel == constant.StatusRunning {
updates["panel"] = constant.StatusFailed
}
if statu.PanelInfo == constant.StatusRunning {
updates["panel_info"] = constant.StatusFailed
}
if statu.DaemonJson == constant.StatusRunning {
updates["daemon_json"] = constant.StatusFailed
}
if statu.AppData == constant.StatusRunning {
updates["app_data"] = constant.StatusFailed
}
if statu.PanelData == constant.StatusRunning {
updates["panel_data"] = constant.StatusFailed
}
if statu.BackupData == constant.StatusRunning {
updates["backup_data"] = constant.StatusFailed
}
if statu.Compress == constant.StatusRunning {
updates["compress"] = constant.StatusFailed
}
if statu.Upload == constant.StatusUploading {
updates["upload"] = constant.StatusFailed
}
if len(updates) != 0 {
_ = snapRepo.UpdateStatus(statu.ID, updates)
}
}
}
-4
View File
@@ -38,10 +38,6 @@ func Init() {
migrations.AddRemoteDB,
migrations.UpdateRedisParam,
migrations.UpdateCronjobWithDb,
migrations.AddTableFirewall,
migrations.AddDatabases,
migrations.UpdateDatabase,
migrations.UpdateAppInstallResource,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
+38 -227
View File
@@ -1,14 +1,13 @@
package migrations
import (
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/service"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/common"
@@ -486,23 +485,40 @@ var EncryptHostPassword = &gormigrate.Migration{
var AddRemoteDB = &gormigrate.Migration{
ID: "20230724-add-remote-db",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Database{}, &model.DatabaseMysql{}); err != nil {
if err := tx.AutoMigrate(&model.RemoteDB{}, &model.DatabaseMysql{}); err != nil {
return err
}
installRepo := repo.NewIAppInstallRepo()
mysqlInfo, err := installRepo.LoadBaseInfo("mysql", "")
if err == nil {
if err := tx.Create(&model.Database{
Name: "local",
Type: "mysql",
Version: mysqlInfo.Version,
From: "local",
Address: "127.0.0.1",
Username: "root",
Password: mysqlInfo.Password,
}).Error; err != nil {
return err
var (
app model.App
appInstall model.AppInstall
)
if err := global.DB.Where("key = ?", "mysql").First(&app).Error; err != nil {
return nil
}
if err := global.DB.Where("app_id = ?", app.ID).First(&appInstall).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return err
}
envMap := make(map[string]interface{})
if err := json.Unmarshal([]byte(appInstall.Env), &envMap); err != nil {
return err
}
password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string)
if !ok {
return errors.New("error password in app env")
}
if err := tx.Create(&model.RemoteDB{
Name: "local",
Type: "mysql",
Version: appInstall.Version,
From: "local",
Address: "127.0.0.1",
Username: "root",
Password: password,
}).Error; err != nil {
return err
}
return nil
},
@@ -515,10 +531,10 @@ var UpdateRedisParam = &gormigrate.Migration{
app model.App
appInstall model.AppInstall
)
if err := tx.Where("key = ?", "redis").First(&app).Error; err != nil {
if err := global.DB.Where("key = ?", "redis").First(&app).Error; err != nil {
return nil
}
if err := tx.Where("app_id = ?", app.ID).First(&appInstall).Error; err != nil {
if err := global.DB.Where("app_id = ?", app.ID).First(&appInstall).Error; err != nil {
return nil
}
appInstall.Param = strings.ReplaceAll(appInstall.Param, "PANEL_DB_ROOT_PASSWORD", "PANEL_REDIS_ROOT_PASSWORD")
@@ -528,6 +544,7 @@ var UpdateRedisParam = &gormigrate.Migration{
return err
}
return nil
},
}
@@ -535,13 +552,13 @@ var UpdateCronjobWithDb = &gormigrate.Migration{
ID: "20230809-update-cronjob-with-db",
Migrate: func(tx *gorm.DB) error {
var cronjobs []model.Cronjob
if err := tx.Where("type = ? AND db_name != ?", "database", "all").Find(&cronjobs).Error; err != nil {
if err := global.DB.Where("type = ? AND db_name != ?", "database", "all").Find(&cronjobs).Error; err != nil {
return nil
}
for _, job := range cronjobs {
var db model.DatabaseMysql
if err := tx.Where("name = ?", job.DBName).First(&db).Error; err != nil {
if err := global.DB.Where("name = ?", job.DBName).First(&db).Error; err != nil {
continue
}
if err := tx.Model(&model.Cronjob{}).
@@ -553,209 +570,3 @@ var UpdateCronjobWithDb = &gormigrate.Migration{
return nil
},
}
var AddTableFirewall = &gormigrate.Migration{
ID: "20230908-add-table-firewall",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Firewall{}, model.SnapshotStatus{}, &model.Cronjob{}); err != nil {
return err
}
_ = tx.Exec("alter table remote_dbs rename to databases;").Error
if err := tx.AutoMigrate(&model.Database{}); err != nil {
return err
}
return nil
},
}
var AddDatabases = &gormigrate.Migration{
ID: "20230831-add-databases",
Migrate: func(tx *gorm.DB) error {
installRepo := repo.NewIAppInstallRepo()
mysqlInfo, err := installRepo.LoadBaseInfo("mysql", "")
if err == nil {
var mysqlDb model.Database
_ = tx.Where("name = ?", mysqlInfo.Name).First(&mysqlDb).Error
if mysqlDb.ID == 0 {
if err := tx.Create(&model.Database{
AppInstallID: mysqlInfo.ID,
Name: mysqlInfo.Name,
Type: "mysql",
Version: mysqlInfo.Version,
From: "local",
Address: mysqlInfo.ServiceName,
Port: service.DatabaseKeys["mysql"],
Username: "root",
Password: mysqlInfo.Password,
}).Error; err != nil {
return err
}
}
}
mariadbInfo, err := installRepo.LoadBaseInfo("mariadb", "")
if err == nil {
if err := tx.Create(&model.Database{
AppInstallID: mariadbInfo.ID,
Name: mariadbInfo.Name,
Type: "mariadb",
Version: mariadbInfo.Version,
From: "local",
Address: mariadbInfo.ServiceName,
Port: service.DatabaseKeys["mariadb"],
Username: "root",
Password: mariadbInfo.Password,
}).Error; err != nil {
return err
}
}
redisInfo, err := installRepo.LoadBaseInfo("redis", "")
if err == nil {
if err := tx.Create(&model.Database{
AppInstallID: redisInfo.ID,
Name: redisInfo.Name,
Type: "redis",
Version: redisInfo.Version,
From: "local",
Address: redisInfo.ServiceName,
Port: service.DatabaseKeys["redis"],
Username: "root",
Password: redisInfo.Password,
}).Error; err != nil {
return err
}
}
pgInfo, err := installRepo.LoadBaseInfo("postgresql", "")
if err == nil {
if err := tx.Create(&model.Database{
AppInstallID: pgInfo.ID,
Name: pgInfo.Name,
Type: "postgresql",
Version: pgInfo.Version,
From: "local",
Address: pgInfo.ServiceName,
Port: service.DatabaseKeys["postgresql"],
Username: pgInfo.UserName,
Password: pgInfo.Password,
}).Error; err != nil {
return err
}
}
mongodbInfo, err := installRepo.LoadBaseInfo("mongodb", "")
if err == nil {
if err := tx.Create(&model.Database{
AppInstallID: mongodbInfo.ID,
Name: mongodbInfo.Name,
Type: "mongodb",
Version: mongodbInfo.Version,
From: "local",
Address: mongodbInfo.ServiceName,
Port: service.DatabaseKeys["mongodb"],
Username: mongodbInfo.UserName,
Password: mongodbInfo.Password,
}).Error; err != nil {
return err
}
}
memcachedInfo, err := installRepo.LoadBaseInfo("memcached", "")
if err == nil {
if err := tx.Create(&model.Database{
AppInstallID: memcachedInfo.ID,
Name: memcachedInfo.Name,
Type: "memcached",
Version: memcachedInfo.Version,
From: "local",
Address: memcachedInfo.ServiceName,
Port: service.DatabaseKeys["memcached"],
Username: "root",
Password: memcachedInfo.Password,
}).Error; err != nil {
return err
}
}
return nil
},
}
var UpdateDatabase = &gormigrate.Migration{
ID: "20230831-update-database",
Migrate: func(tx *gorm.DB) error {
if err := tx.Model(&model.DatabaseMysql{}).Where("`from` != ?", "local").Updates(map[string]interface{}{
"from": "remote",
}).Error; err != nil {
return err
}
var datas []model.Database
if err := tx.Find(&datas).Error; err != nil {
return nil
}
for _, data := range datas {
if data.Name == "local" && data.Address == "127.0.0.1" && data.Type == "mysql" {
installRepo := repo.NewIAppInstallRepo()
mysqlInfo, err := installRepo.LoadBaseInfo("mysql", "")
if err != nil {
continue
}
pass, err := encrypt.StringEncrypt(data.Password)
if err != nil {
global.LOG.Errorf("encrypt database %s password failed, err: %v", data.Name, err)
continue
}
if err := tx.Model(&model.Database{}).Where("id = ?", data.ID).Updates(map[string]interface{}{
"app_install_id": mysqlInfo.ID,
"name": mysqlInfo.Name,
"password": pass,
"port": service.DatabaseKeys["mysql"],
"address": mysqlInfo.ServiceName,
}).Error; err != nil {
global.LOG.Errorf("updata database %s info failed, err: %v", data.Name, err)
}
} else {
pass, err := encrypt.StringEncrypt(data.Password)
if err != nil {
global.LOG.Errorf("encrypt database %s password failed, err: %v", data.Name, err)
continue
}
if err := tx.Model(&model.Database{}).Where("id = ?", data.ID).Updates(map[string]interface{}{
"password": pass,
}).Error; err != nil {
global.LOG.Errorf("updata database %s info failed, err: %v", data.Name, err)
}
}
}
var mysqls []model.DatabaseMysql
if err := tx.Find(&mysqls).Error; err != nil {
return nil
}
for _, data := range mysqls {
pass, err := encrypt.StringEncrypt(data.Password)
if err != nil {
global.LOG.Errorf("encrypt database db %s password failed, err: %v", data.Name, err)
continue
}
if err := tx.Model(&model.DatabaseMysql{}).Where("id = ?", data.ID).Updates(map[string]interface{}{
"password": pass,
}).Error; err != nil {
global.LOG.Errorf("updata database db %s info failed, err: %v", data.Name, err)
}
}
return nil
},
}
var UpdateAppInstallResource = &gormigrate.Migration{
ID: "20230831-update-app_install_resource",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.AppInstallResource{}); err != nil {
return err
}
if err := tx.Model(&model.AppInstallResource{}).Where("1 = 1").Updates(map[string]interface{}{
"from": "local",
}).Error; err != nil {
return err
}
return nil
},
}
+4 -5
View File
@@ -24,17 +24,16 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) {
appRouter.POST("/install", baseApi.InstallApp)
appRouter.GET("/tags", baseApi.GetAppTags)
appRouter.GET("/installed/:appInstallId/versions", baseApi.GetUpdateVersions)
appRouter.POST("/installed/check", baseApi.CheckAppInstalled)
appRouter.POST("/installed/loadport", baseApi.LoadPort)
appRouter.POST("/installed/conninfo", baseApi.LoadConnInfo)
appRouter.GET("/installed/check/:key", baseApi.CheckAppInstalled)
appRouter.GET("/installed/loadport/:key", baseApi.LoadPort)
appRouter.GET("/installed/conninfo/:key", baseApi.LoadConnInfo)
appRouter.GET("/installed/delete/check/:appInstallId", baseApi.DeleteCheck)
appRouter.POST("/installed/search", baseApi.SearchAppInstalled)
appRouter.GET("/installed/list", baseApi.ListAppInstalled)
appRouter.POST("/installed/op", baseApi.OperateInstalled)
appRouter.POST("/installed/sync", baseApi.SyncInstalled)
appRouter.POST("/installed/port/change", baseApi.ChangeAppPort)
appRouter.GET("/services/:key", baseApi.GetServices)
appRouter.POST("/installed/conf", baseApi.GetDefaultConfig)
appRouter.GET("/installed/conf/:key", baseApi.GetDefaultConfig)
appRouter.GET("/installed/params/:appInstallId", baseApi.GetParams)
appRouter.POST("/installed/params/update", baseApi.UpdateInstalled)
appRouter.POST("/installed/ignore", baseApi.IgnoreUpgrade)
+12 -12
View File
@@ -17,7 +17,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
baseApi := v1.ApiGroupApp.BaseApi
{
cmdRouter.POST("", baseApi.CreateMysql)
cmdRouter.POST("load", baseApi.LoadDBFromRemote)
cmdRouter.GET("load/:from", baseApi.LoadDBFromRemote)
cmdRouter.POST("/change/access", baseApi.ChangeMysqlAccess)
cmdRouter.POST("/change/password", baseApi.ChangeMysqlPassword)
cmdRouter.POST("/del/check", baseApi.DeleteCheckMysql)
@@ -27,10 +27,10 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/conffile/update", baseApi.UpdateMysqlConfByFile)
cmdRouter.POST("/search", baseApi.SearchMysql)
cmdRouter.POST("/load/file", baseApi.LoadDatabaseFile)
cmdRouter.POST("/variables", baseApi.LoadVariables)
cmdRouter.POST("/status", baseApi.LoadStatus)
cmdRouter.POST("/baseinfo", baseApi.LoadBaseinfo)
cmdRouter.POST("/remote", baseApi.LoadRemoteAccess)
cmdRouter.GET("/variables", baseApi.LoadVariables)
cmdRouter.GET("/status", baseApi.LoadStatus)
cmdRouter.GET("/baseinfo", baseApi.LoadBaseinfo)
cmdRouter.GET("/remote", baseApi.LoadRemoteAccess)
cmdRouter.GET("/options", baseApi.ListDBName)
cmdRouter.GET("/redis/persistence/conf", baseApi.LoadPersistenceConf)
@@ -43,12 +43,12 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/redis/conffile/update", baseApi.UpdateRedisConfByFile)
cmdRouter.POST("/redis/persistence/update", baseApi.UpdateRedisPersistenceConf)
cmdRouter.POST("/db/check", baseApi.CheckDatabase)
cmdRouter.POST("/db", baseApi.CreateDatabase)
cmdRouter.GET("/db/:name", baseApi.GetDatabase)
cmdRouter.GET("/db/list/:type", baseApi.ListDatabase)
cmdRouter.POST("/db/update", baseApi.UpdateDatabase)
cmdRouter.POST("/db/search", baseApi.SearchDatabase)
cmdRouter.POST("/db/del", baseApi.DeleteDatabase)
cmdRouter.POST("/remote/check", baseApi.CheckeRemoteDB)
cmdRouter.POST("/remote", baseApi.CreateRemoteDB)
cmdRouter.GET("/remote/:name", baseApi.GetRemoteDB)
cmdRouter.GET("/remote/list/:type", baseApi.ListRemoteDB)
cmdRouter.POST("/remote/update", baseApi.UpdateRemoteDB)
cmdRouter.POST("/remote/search", baseApi.SearchRemoteDB)
cmdRouter.POST("/remote/del", baseApi.DeleteRemoteDB)
}
}
+1 -1
View File
@@ -33,7 +33,6 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
hostRouter.POST("/firewall/batch", baseApi.BatchOperateRule)
hostRouter.POST("/firewall/update/port", baseApi.UpdatePortRule)
hostRouter.POST("/firewall/update/addr", baseApi.UpdateAddrRule)
hostRouter.POST("/firewall/update/description", baseApi.UpdateFirewallDescription)
hostRouter.GET("/ssh/conf", baseApi.LoadSSHConf)
hostRouter.POST("/ssh/search", baseApi.GetSSHInfo)
@@ -55,6 +54,7 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
hostRouter.POST("/tool/operate", baseApi.OperateTool)
hostRouter.POST("/tool/config", baseApi.OperateToolConfig)
hostRouter.POST("/tool/log", baseApi.GetToolLog)
hostRouter.POST("/tool/supervisor/process/load", baseApi.LoadProcessStatus)
hostRouter.POST("/tool/supervisor/process", baseApi.OperateProcess)
hostRouter.GET("/tool/supervisor/process", baseApi.GetProcess)
hostRouter.POST("/tool/supervisor/process/file", baseApi.GetProcessFile)
-1
View File
@@ -34,7 +34,6 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
settingRouter.POST("/mfa/bind", baseApi.MFABind)
settingRouter.POST("/snapshot", baseApi.CreateSnapshot)
settingRouter.POST("/snapshot/status", baseApi.LoadSnapShotStatus)
settingRouter.POST("/snapshot/search", baseApi.SearchSnapshot)
settingRouter.POST("/snapshot/import", baseApi.ImportSnapshot)
settingRouter.POST("/snapshot/del", baseApi.DeleteSnapshot)
-1
View File
@@ -53,7 +53,6 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
groupRouter.POST("/dir/update", baseApi.UpdateSiteDir)
groupRouter.POST("/dir/permission", baseApi.UpdateSiteDirPermission)
groupRouter.POST("/dir", baseApi.GetDirConfig)
groupRouter.POST("/proxies", baseApi.GetProxyConfig)
groupRouter.POST("/proxies/update", baseApi.UpdateProxyConfig)
-29
View File
@@ -141,35 +141,6 @@ func ExecWithCheck(name string, a ...string) (string, error) {
return stdout.String(), nil
}
func ExecScript(scriptPath, workDir string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
cmd := exec.Command("bash", scriptPath)
cmd.Dir = workDir
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if ctx.Err() == context.DeadlineExceeded {
return "", buserr.New(constant.ErrCmdTimeout)
}
if err != nil {
errMsg := ""
if len(stderr.String()) != 0 {
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
}
if len(stdout.String()) != 0 {
if len(errMsg) != 0 {
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
} else {
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
}
}
return errMsg, err
}
return stdout.String(), nil
}
func CheckIllegal(args ...string) bool {
if args == nil {
return false
+3 -28
View File
@@ -14,7 +14,6 @@ import (
"time"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/mozillazg/go-pinyin"
)
func CompareVersion(version1 string, version2 string) bool {
@@ -114,13 +113,6 @@ func ScanUDPPort(port int) bool {
return false
}
func ScanPortWithProto(port int, proto string) bool {
if proto == "udp" {
return ScanUDPPort(port)
}
return ScanPort(port)
}
func ExistWithStrArray(str string, arr []string) bool {
for _, a := range arr {
if strings.Contains(a, str) {
@@ -147,16 +139,13 @@ func RemoveRepeatElement(a interface{}) (ret []interface{}) {
}
func LoadSizeUnit(value float64) string {
if value > 1073741824 {
return fmt.Sprintf("%.2fG", value/1073741824)
}
if value > 1048576 {
return fmt.Sprintf("%.2fM", value/1048576)
return fmt.Sprintf("%vM", value/1048576)
}
if value > 1024 {
return fmt.Sprintf("%.2fK", value/1024)
return fmt.Sprintf("%vK", value/1024)
}
return fmt.Sprintf("%.2f", value)
return fmt.Sprintf("%v", value)
}
func LoadTimeZone() string {
@@ -184,17 +173,3 @@ func LoadTimeZoneByCmd() string {
}
return fields[2]
}
func ConvertToPinyin(text string) string {
args := pinyin.NewArgs()
args.Fallback = func(r rune, a pinyin.Args) []string {
return []string{string(r)}
}
p := pinyin.Pinyin(text, args)
var strArr []string
for i := 0; i < len(p); i++ {
strArr = append(strArr, strings.Join(p[i], ""))
}
return strings.Join(strArr, "")
}
+2 -10
View File
@@ -42,10 +42,7 @@ func (c Client) ListAllContainers() ([]types.Container, error) {
}
func (c Client) ListContainersByName(names []string) ([]types.Container, error) {
var (
options types.ContainerListOptions
res []types.Container
)
var options types.ContainerListOptions
options.All = true
if len(names) > 0 {
var array []filters.KeyValuePair
@@ -58,12 +55,7 @@ func (c Client) ListContainersByName(names []string) ([]types.Container, error)
if err != nil {
return nil, err
}
for _, container := range containers {
if container.Names[0] == "/"+names[0] {
res = append(res, container)
}
}
return res, nil
return containers, nil
}
func (c Client) CreateNetwork(name string) error {
+3 -17
View File
@@ -8,23 +8,16 @@ import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
)
func StringEncrypt(text string) (string, error) {
if len(text) == 0 {
return "", nil
}
if len(global.CONF.System.EncryptKey) == 0 {
var encryptSetting model.Setting
if err := global.DB.Where("key = ?", "EncryptKey").First(&encryptSetting).Error; err != nil {
return "", err
}
global.CONF.System.EncryptKey = encryptSetting.Value
return "", errors.New("it is not possible to encrypt an empty string.")
}
key := global.CONF.System.EncryptKey
pass := []byte(text)
@@ -38,14 +31,7 @@ func StringEncrypt(text string) (string, error) {
func StringDecrypt(text string) (string, error) {
if len(text) == 0 {
return "", nil
}
if len(global.CONF.System.EncryptKey) == 0 {
var encryptSetting model.Setting
if err := global.DB.Where("key = ?", "EncryptKey").First(&encryptSetting).Error; err != nil {
return "", err
}
global.CONF.System.EncryptKey = encryptSetting.Value
return "", errors.New("it is not possible to decrypt an empty string.")
}
key := global.CONF.System.EncryptKey
bytesPass, err := base64.StdEncoding.DecodeString(text)
+3 -3
View File
@@ -125,9 +125,9 @@ func (f FileOp) Chown(dst string, uid int, gid int) error {
}
func (f FileOp) ChownR(dst string, uid string, gid string, sub bool) error {
cmdStr := fmt.Sprintf(`chown %s:%s "%s"`, uid, gid, dst)
cmdStr := fmt.Sprintf("chown %s:%s %s", uid, gid, dst)
if sub {
cmdStr = fmt.Sprintf(`chown -R %s:%s "%s"`, uid, gid, dst)
cmdStr = fmt.Sprintf("chown -R %s:%s %s", uid, gid, dst)
}
if cmd.HasNoPasswordSudo() {
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
@@ -142,7 +142,7 @@ func (f FileOp) ChownR(dst string, uid string, gid string, sub bool) error {
}
func (f FileOp) ChmodR(dst string, mode int64) error {
cmdStr := fmt.Sprintf(`chmod -R %v "%s"`, fmt.Sprintf("%04o", mode), dst)
cmdStr := fmt.Sprintf("chmod -R %v %s", fmt.Sprintf("%04o", mode), dst)
if cmd.HasNoPasswordSudo() {
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
}
-7
View File
@@ -10,7 +10,6 @@ import (
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
@@ -24,8 +23,6 @@ type FileInfo struct {
Name string `json:"name"`
User string `json:"user"`
Group string `json:"group"`
Uid string `json:"uid"`
Gid string `json:"gid"`
Extension string `json:"extension"`
Content string `json:"content"`
Size int64 `json:"size"`
@@ -80,8 +77,6 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
IsHidden: IsHidden(op.Path),
Mode: fmt.Sprintf("%04o", info.Mode().Perm()),
User: GetUsername(info.Sys().(*syscall.Stat_t).Uid),
Uid: strconv.FormatUint(uint64(info.Sys().(*syscall.Stat_t).Uid), 10),
Gid: strconv.FormatUint(uint64(info.Sys().(*syscall.Stat_t).Gid), 10),
Group: GetGroup(info.Sys().(*syscall.Stat_t).Gid),
MimeType: GetMimeType(op.Path),
}
@@ -213,8 +208,6 @@ func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string,
Mode: fmt.Sprintf("%04o", df.Mode().Perm()),
User: GetUsername(df.Sys().(*syscall.Stat_t).Uid),
Group: GetGroup(df.Sys().(*syscall.Stat_t).Gid),
Uid: strconv.FormatUint(uint64(df.Sys().(*syscall.Stat_t).Uid), 10),
Gid: strconv.FormatUint(uint64(df.Sys().(*syscall.Stat_t).Gid), 10),
}
if isSymlink {
-34
View File
@@ -1,7 +1,6 @@
package files
import (
"bufio"
"github.com/spf13/afero"
"net/http"
"os"
@@ -76,36 +75,3 @@ const dotCharacter = 46
func IsHidden(path string) bool {
return path[0] == dotCharacter
}
func ReadFileByLine(filename string, page, pageSize int) ([]string, bool, error) {
file, err := os.Open(filename)
if err != nil {
return nil, false, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
var lines []string
currentLine := 0
startLine := (page - 1) * pageSize
endLine := startLine + pageSize
for scanner.Scan() {
if currentLine >= startLine && currentLine < endLine {
lines = append(lines, scanner.Text())
}
currentLine++
if currentLine >= endLine {
break
}
}
if err := scanner.Err(); err != nil {
return nil, false, err
}
isEndOfFile := currentLine < endLine
return lines, isEndOfFile, nil
}
+2 -3
View File
@@ -7,9 +7,8 @@ type FireInfo struct {
Protocol string `json:"protocol"` // tcp udp tcp/udp
Strategy string `json:"strategy"` // accept drop
APPName string `json:"appName"`
IsUsed bool `json:"isUsed"`
Description string `json:"description"`
APPName string `json:"appName"`
IsUsed bool `json:"isUsed"`
}
type Forward struct {
+2 -2
View File
@@ -28,7 +28,7 @@ type MysqlClient interface {
func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
if conn.From == "local" {
connArgs := []string{"exec", conn.Address, "mysql", "-u" + conn.Username, "-p" + conn.Password, "-e"}
return client.NewLocal(connArgs, conn.Address, conn.Password, conn.Database), nil
return client.NewLocal(connArgs, conn.Address, conn.Password, conn.From), nil
}
connArgs := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8", conn.Username, conn.Password, conn.Address, conn.Port)
@@ -48,7 +48,7 @@ func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
return client.NewRemote(client.Remote{
Client: db,
Database: conn.Database,
From: conn.From,
User: conn.Username,
Password: conn.Password,
Address: conn.Address,
+6 -38
View File
@@ -1,7 +1,6 @@
package client
import (
mathRand "math/rand"
"strings"
"github.com/1Panel-dev/1Panel/backend/utils/common"
@@ -9,7 +8,6 @@ import (
type DBInfo struct {
From string `json:"from"`
Database string `json:"database"`
Address string `json:"address"`
Port uint `json:"port"`
Username string `json:"userName"`
@@ -95,44 +93,14 @@ var formatMap = map[string]string{
}
func loadNameByDB(name, version string) string {
nameItem := common.ConvertToPinyin(name)
if strings.HasPrefix(version, "5.6") {
if len(nameItem) <= 16 {
return nameItem
if len(name) <= 16 {
return name
}
return strings.TrimSuffix(nameItem[:10], "_") + "_" + common.RandStr(5)
return strings.TrimSuffix(name[:10], "_") + "_" + common.RandStr(5)
}
if len(nameItem) <= 32 {
return nameItem
if len(name) <= 32 {
return name
}
return strings.TrimSuffix(nameItem[:25], "_") + "_" + common.RandStr(5)
}
func randomPassword(user string) string {
passwdItem := user
if len(user) > 6 {
passwdItem = user[:6]
}
num := []rune("1234567890")
uppercase := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
lowercase := []rune("abcdefghijklmnopqrstuvwxyz")
special := []rune(".%@!~_-")
b := make([]rune, 10)
for i := 0; i < 2; i++ {
b[i] = lowercase[mathRand.Intn(len(lowercase))]
}
for i := 2; i < 4; i++ {
b[i] = uppercase[mathRand.Intn(len(uppercase))]
}
b[4] = special[mathRand.Intn(len(special))]
for i := 5; i < 9; i++ {
b[i] = num[mathRand.Intn(len(num))]
}
for i := len(b) - 1; i > 0; i-- {
j := mathRand.Intn(i + 1)
b[i], b[j] = b[j], b[i]
}
return passwdItem + "-" + (string(b))
return strings.TrimSuffix(name[:25], "_") + "_" + common.RandStr(5)
}
+12 -15
View File
@@ -14,24 +14,25 @@ import (
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
)
type Local struct {
PrefixCommand []string
Database string
From string
Password string
ContainerName string
}
func NewLocal(command []string, containerName, password, database string) *Local {
return &Local{PrefixCommand: command, ContainerName: containerName, Password: password, Database: database}
func NewLocal(command []string, containerName, password, from string) *Local {
return &Local{PrefixCommand: command, ContainerName: containerName, Password: password, From: from}
}
func (r *Local) Create(info CreateInfo) error {
createSql := fmt.Sprintf("create database `%s` default character set %s collate %s", info.Name, info.Format, formatMap[info.Format])
if err := r.ExecSQL(createSql, info.Timeout); err != nil {
if strings.Contains(strings.ToLower(err.Error()), "error 1007") {
if strings.Contains(err.Error(), "ERROR 1007") {
return buserr.New(constant.ErrDatabaseIsExist)
}
return err
@@ -60,7 +61,7 @@ func (r *Local) CreateUser(info CreateInfo, withDeleteDB bool) error {
for _, user := range userlist {
if err := r.ExecSQL(fmt.Sprintf("create user %s identified by '%s';", user, info.Password), info.Timeout); err != nil {
if strings.Contains(strings.ToLower(err.Error()), "error 1396") {
if strings.Contains(err.Error(), "ERROR 1396") {
return buserr.New(constant.ErrUserIsExist)
}
_ = r.Delete(DeleteInfo{
@@ -78,8 +79,6 @@ func (r *Local) CreateUser(info CreateInfo, withDeleteDB bool) error {
}
if strings.HasPrefix(info.Version, "5.7") || strings.HasPrefix(info.Version, "5.6") {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, info.Password)
} else {
grantStr = grantStr + " with grant option;"
}
if err := r.ExecSQL(grantStr, info.Timeout); err != nil {
_ = r.Delete(DeleteInfo{
@@ -148,7 +147,7 @@ func (r *Local) ChangePassword(info PasswordChangeInfo) error {
for _, user := range userlist {
passwordChangeSql := fmt.Sprintf("set password for %s = password('%s')", user, info.Password)
if !strings.HasPrefix(info.Version, "5.7") && !strings.HasPrefix(info.Version, "5.6") {
passwordChangeSql = fmt.Sprintf("ALTER USER %s IDENTIFIED BY '%s';", user, info.Password)
passwordChangeSql = fmt.Sprintf("alter user %s identified by '%s';", user, info.Password)
}
if err := r.ExecSQL(passwordChangeSql, info.Timeout); err != nil {
return err
@@ -165,7 +164,7 @@ func (r *Local) ChangePassword(info PasswordChangeInfo) error {
if host == "%" || host == "localhost" {
passwordRootChangeCMD := fmt.Sprintf("set password for 'root'@'%s' = password('%s')", host, info.Password)
if !strings.HasPrefix(info.Version, "5.7") && !strings.HasPrefix(info.Version, "5.6") {
passwordRootChangeCMD = fmt.Sprintf("alter user 'root'@'%s' identified by '%s';", host, info.Password)
passwordRootChangeCMD = fmt.Sprintf("alter user 'root'@'%s' identified with mysql_native_password BY '%s';", host, info.Password)
}
if err := r.ExecSQL(passwordRootChangeCMD, info.Timeout); err != nil {
return err
@@ -273,10 +272,9 @@ func (r *Local) SyncDB(version string) ([]SyncDBInfo, error) {
continue
}
dataItem := SyncDBInfo{
Name: parts[0],
From: "local",
MysqlName: r.Database,
Format: parts[1],
Name: parts[0],
From: r.From,
Format: parts[1],
}
userLines, err := r.ExecSQLForRows(fmt.Sprintf("select user,host from mysql.db where db = '%s'", parts[0]), 300)
if err != nil {
@@ -308,13 +306,12 @@ func (r *Local) SyncDB(version string) ([]SyncDBInfo, error) {
}
if len(dataItem.Username) == 0 {
dataItem.Username = loadNameByDB(parts[0], version)
dataItem.Password = randomPassword(dataItem.Username)
if err := r.CreateUser(CreateInfo{
Name: parts[0],
Format: parts[1],
Version: version,
Username: dataItem.Username,
Password: dataItem.Password,
Password: common.RandStr(16),
Permission: "%",
Timeout: 300,
}, false); err != nil {
+11 -13
View File
@@ -12,13 +12,14 @@ import (
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/mysql/helper"
)
type Remote struct {
Client *sql.DB
Database string
From string
User string
Password string
Address string
@@ -32,7 +33,7 @@ func NewRemote(db Remote) *Remote {
func (r *Remote) Create(info CreateInfo) error {
createSql := fmt.Sprintf("create database `%s` default character set %s collate %s", info.Name, info.Format, formatMap[info.Format])
if err := r.ExecSQL(createSql, info.Timeout); err != nil {
if strings.Contains(strings.ToLower(err.Error()), "error 1007") {
if strings.Contains(err.Error(), "ERROR 1007") {
return buserr.New(constant.ErrDatabaseIsExist)
}
return err
@@ -61,9 +62,6 @@ func (r *Remote) CreateUser(info CreateInfo, withDeleteDB bool) error {
for _, user := range userlist {
if err := r.ExecSQL(fmt.Sprintf("create user %s identified by '%s';", user, info.Password), info.Timeout); err != nil {
if strings.Contains(strings.ToLower(err.Error()), "error 1396") {
return buserr.New(constant.ErrUserIsExist)
}
if withDeleteDB {
_ = r.Delete(DeleteInfo{
Name: info.Name,
@@ -72,6 +70,9 @@ func (r *Remote) CreateUser(info CreateInfo, withDeleteDB bool) error {
Permission: info.Permission,
ForceDelete: true,
Timeout: 300})
if strings.Contains(err.Error(), "ERROR 1396") {
return buserr.New(constant.ErrUserIsExist)
}
}
return err
}
@@ -81,8 +82,6 @@ func (r *Remote) CreateUser(info CreateInfo, withDeleteDB bool) error {
}
if strings.HasPrefix(info.Version, "5.7") || strings.HasPrefix(info.Version, "5.6") {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, info.Password)
} else {
grantStr = grantStr + " with grant option;"
}
if err := r.ExecSQL(grantStr, info.Timeout); err != nil {
if withDeleteDB {
@@ -153,7 +152,7 @@ func (r *Remote) ChangePassword(info PasswordChangeInfo) error {
for _, user := range userlist {
passwordChangeSql := fmt.Sprintf("set password for %s = password('%s')", user, info.Password)
if !strings.HasPrefix(info.Version, "5.7") && !strings.HasPrefix(info.Version, "5.6") {
passwordChangeSql = fmt.Sprintf("ALTER USER %s IDENTIFIED BY '%s';", user, info.Password)
passwordChangeSql = fmt.Sprintf("ALTER USER %s IDENTIFIED WITH mysql_native_password BY '%s';", user, info.Password)
}
if err := r.ExecSQL(passwordChangeSql, info.Timeout); err != nil {
return err
@@ -170,7 +169,7 @@ func (r *Remote) ChangePassword(info PasswordChangeInfo) error {
if host == "%" || host == "localhost" {
passwordRootChangeCMD := fmt.Sprintf("set password for 'root'@'%s' = password('%s')", host, info.Password)
if !strings.HasPrefix(info.Version, "5.7") && !strings.HasPrefix(info.Version, "5.6") {
passwordRootChangeCMD = fmt.Sprintf("alter user 'root'@'%s' identified by '%s';", host, info.Password)
passwordRootChangeCMD = fmt.Sprintf("alter user 'root'@'%s' identified with mysql_native_password BY '%s';", host, info.Password)
}
if err := r.ExecSQL(passwordRootChangeCMD, info.Timeout); err != nil {
return err
@@ -284,8 +283,8 @@ func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) {
}
dataItem := SyncDBInfo{
Name: dbName,
From: "remote",
MysqlName: r.Database,
From: r.From,
MysqlName: r.From,
Format: charsetName,
}
userRows, err := r.Client.Query("select user,host from mysql.db where db = ?", dbName)
@@ -318,13 +317,12 @@ func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) {
}
if len(dataItem.Username) == 0 {
dataItem.Username = loadNameByDB(dbName, version)
dataItem.Password = randomPassword(dataItem.Username)
if err := r.CreateUser(CreateInfo{
Name: dbName,
Format: charsetName,
Version: version,
Username: dataItem.Username,
Password: dataItem.Password,
Password: common.RandStr(16),
Permission: "%",
Timeout: 300,
}, false); err != nil {
-97
View File
@@ -1,97 +0,0 @@
package cmd
import (
"fmt"
"os"
"path"
"sort"
"strings"
cmdUtils "github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
func init() {
RootCmd.AddCommand(restoreCmd)
}
var restoreCmd = &cobra.Command{
Use: "restore",
Short: "回滚 1Panel 服务及数据",
RunE: func(cmd *cobra.Command, args []string) error {
if !isRoot() {
fmt.Println("请使用 sudo 1pctl restore 或者切换到 root 用户")
return nil
}
stdout, err := cmdUtils.Exec("grep '^BASE_DIR=' /usr/bin/1pctl | cut -d'=' -f2")
if err != nil {
return fmt.Errorf("handle load `BASE_DIR` failed, err: %v", err)
}
baseDir := strings.ReplaceAll(stdout, "\n", "")
upgradeDir := path.Join(baseDir, "1panel", "tmp", "upgrade")
tmpPath, err := loadRestorePath(upgradeDir)
if err != nil {
return err
}
if tmpPath == "暂无可回滚文件" {
fmt.Println("暂无可回滚文件")
return nil
}
tmpPath = path.Join(upgradeDir, tmpPath, "original")
fmt.Printf("(0/4) 开始从 %s 目录回滚 1Panel 服务及数据... \n", tmpPath)
if err := cpBinary(path.Join(tmpPath, "1panel"), "/usr/local/bin/1panel"); err != nil {
return err
}
fmt.Println("(1/4) 1panel 二进制回滚成功")
if err := cpBinary(path.Join(tmpPath, "1pctl"), "/usr/local/bin/1pctl"); err != nil {
return err
}
fmt.Println("(2/4) 1panel 脚本回滚成功")
if err := cpBinary(path.Join(tmpPath, "1panel.service"), "/etc/systemd/system/1panel.service"); err != nil {
return err
}
fmt.Println("(3/4) 1panel 服务回滚成功")
if err := cpBinary(path.Join(tmpPath, "1Panel.db"), path.Join(baseDir, "1panel", "db", "1Panel.db")); err != nil {
return err
}
fmt.Printf("(4/4) 1panel 数据回滚成功 \n\n")
fmt.Println("回滚成功!正在重启服务,请稍候...")
return nil
},
}
func loadRestorePath(upgradeDir string) (string, error) {
if _, err := os.Stat(upgradeDir); err != nil && os.IsNotExist(err) {
return "暂无可回滚文件", nil
}
files, err := os.ReadDir(upgradeDir)
if err != nil {
return "", err
}
var folders []string
for _, file := range files {
if file.IsDir() {
folders = append(folders, file.Name())
}
}
if len(folders) == 0 {
return "暂无可回滚文件", nil
}
sort.Slice(folders, func(i, j int) bool {
return folders[i] > folders[j]
})
return folders[0], nil
}
func cpBinary(src string, dst string) error {
stderr, err := cmdUtils.Exec(fmt.Sprintf("\\cp -f %s %s", src, dst))
if err != nil {
return errors.New(stderr)
}
return nil
}
+5 -12
View File
@@ -30,7 +30,6 @@ var userinfoCmd = &cobra.Command{
ssl := getSettingByKey(db, "SSL")
entrance := getSettingByKey(db, "SecurityEntrance")
encryptSetting := getSettingByKey(db, "EncryptKey")
address := getSettingByKey(db, "SystemIP")
p := ""
if len(encryptSetting) == 16 {
@@ -40,17 +39,11 @@ var userinfoCmd = &cobra.Command{
p = password
}
protocol := "http"
if ssl == "enable" {
protocol = "https"
}
if address == "" {
address = "$LOCAL_IP"
}
fmt.Printf("面板地址: %s://%s:%s/%s \n", protocol, address, port, entrance)
fmt.Printf("用户名称: %s\n", user)
fmt.Printf("用户密码: %s\n", p)
fmt.Printf("username: %s\n", user)
fmt.Printf("password: %s\n", p)
fmt.Printf("port: %s\n", port)
fmt.Printf("ssl: %s\n", ssl)
fmt.Printf("entrance: %s\n", entrance)
return nil
},
}
+499 -946
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More