mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-09 16:00:29 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04edce94f9 | ||
|
|
ccb81365f2 | ||
|
|
acf608cb7e | ||
|
|
2724708539 | ||
|
|
50589a8d8d | ||
|
|
f06f487e8a | ||
|
|
42dd668e1e | ||
|
|
6cd00a072d | ||
|
|
8faa3b6e51 | ||
|
|
52198e9c0c | ||
|
|
173e3e9cc1 | ||
|
|
40c751cde2 | ||
|
|
a3bf4513e1 | ||
|
|
4e7350aaae | ||
|
|
9ae935d06a | ||
|
|
b6055eb058 | ||
|
|
0e158ffa2b | ||
|
|
cc7260e121 | ||
|
|
43b3ef47f3 | ||
|
|
21755223e1 | ||
|
|
08f0147d81 | ||
|
|
3bcb5800a2 | ||
|
|
aa057772dc | ||
|
|
bf32424458 | ||
|
|
5c0fb405d0 | ||
|
|
279f8f0e6c | ||
|
|
8bc6b409d9 | ||
|
|
5a315a773a | ||
|
|
b9befc72a3 | ||
|
|
cab0c7938d | ||
|
|
a241fb32d2 | ||
|
|
7b4b0bddff | ||
|
|
65662b2e84 | ||
|
|
6f250e63db | ||
|
|
47cfa0c730 | ||
|
|
9837c60a88 | ||
|
|
e991bbe799 | ||
|
|
418863543c | ||
|
|
c027ea21ca | ||
|
|
327e160ea3 | ||
|
|
3a0b3e952b | ||
|
|
16446ecaf3 | ||
|
|
ecb7a2ebee | ||
|
|
49d217e990 | ||
|
|
d1d0ca92ca | ||
|
|
ac91480987 | ||
|
|
a364dbffbf | ||
|
|
9aaf3bf435 | ||
|
|
eff3e8fcc5 | ||
|
|
9d11e56074 | ||
|
|
645e6bbb79 | ||
|
|
9e5a452245 | ||
|
|
6b908d2553 | ||
|
|
6e8f22a4a6 | ||
|
|
f812d9f7cd | ||
|
|
a61487de9f | ||
|
|
9a43b52c62 | ||
|
|
ad8bf09034 | ||
|
|
e75c9a0304 | ||
|
|
c485fe2bd5 | ||
|
|
add4fab794 | ||
|
|
02dce0e3fa | ||
|
|
ae515b079c | ||
|
|
df5a1b3e40 | ||
|
|
278fac6d80 | ||
|
|
3e33a4b16c | ||
|
|
f0eaee82b6 | ||
|
|
4d8118d9ab | ||
|
|
31cd6691c9 | ||
|
|
e509fb0571 | ||
|
|
e6522ded62 | ||
|
|
0a9fc26714 | ||
|
|
ed3d587046 | ||
|
|
38b462eece | ||
|
|
c588c34955 | ||
|
|
fb00ba812a | ||
|
|
0c2d971d72 | ||
|
|
ea17c451a6 | ||
|
|
c00d715b87 | ||
|
|
db443a9f82 | ||
|
|
5b00bfd1c4 | ||
|
|
dbf349ee9d | ||
|
|
f75744e252 | ||
|
|
ecc444db9f | ||
|
|
ba38402a24 | ||
|
|
1a6d237d0f | ||
|
|
78999f97db | ||
|
|
7dacac8846 | ||
|
|
0c6a065994 | ||
|
|
dba3c6f2c1 | ||
|
|
149d44dbbe | ||
|
|
66c824a841 | ||
|
|
a948ece792 | ||
|
|
3da1b22a1b | ||
|
|
ff0ed46554 | ||
|
|
2ed2a7ed8c | ||
|
|
f9d5a445c7 | ||
|
|
9cecd66f3d | ||
|
|
529a7e6ea6 | ||
|
|
d3cd087b91 | ||
|
|
4d2ca1f3a0 | ||
|
|
7b1566f4ac | ||
|
|
7891f9225b | ||
|
|
03f53f7042 | ||
|
|
9f38a78512 | ||
|
|
49e3d45912 | ||
|
|
d1e7b36243 | ||
|
|
3adb200585 | ||
|
|
ff141b21e2 | ||
|
|
b54c79e196 | ||
|
|
b55b930353 | ||
|
|
8b1098fc9d | ||
|
|
ac0f697111 | ||
|
|
7ff9c75bdf | ||
|
|
9f0d957145 | ||
|
|
680e93dcd4 | ||
|
|
f546ffee90 | ||
|
|
6a8bd490bf | ||
|
|
684f20a5dc | ||
|
|
a3c07dd3d3 | ||
|
|
ca0368c931 | ||
|
|
59eff6e27f | ||
|
|
63ae17372d | ||
|
|
f196d029cb | ||
|
|
f9bf6b69fb | ||
|
|
5e47656542 | ||
|
|
d72d2c1167 | ||
|
|
24c87905b1 | ||
|
|
fe7fed02ee | ||
|
|
f4c3aafced | ||
|
|
c1db5886ff | ||
|
|
5dac95c3de | ||
|
|
f8f231253d | ||
|
|
da8a06909b | ||
|
|
e67d9055aa | ||
|
|
c3134e4c2a | ||
|
|
bdd36b3fbc | ||
|
|
d04c4bd425 | ||
|
|
8135f0f598 | ||
|
|
6be8bc0c50 | ||
|
|
8433822021 | ||
|
|
65194ae22b | ||
|
|
89faf01391 |
@@ -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" 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?color=%231890FF" 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>
|
||||
<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>]
|
||||
</p>
|
||||
|
||||
------------------------------
|
||||
|
||||
+2
-2
@@ -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>
|
||||
<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>]
|
||||
</p>
|
||||
|
||||
------------------------------
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<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 ディスプレイ
|
||||
|
||||

|
||||
|
||||
## クイックスタート
|
||||
|
||||
**オンラインでも**
|
||||
|
||||
- アドレス: <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
|
||||
|
||||
[](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.
|
||||
@@ -1,7 +1,6 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
@@ -14,8 +13,8 @@ import (
|
||||
)
|
||||
|
||||
// @Tags App
|
||||
// @Summary List app installed
|
||||
// @Description 获取已安装应用列表
|
||||
// @Summary Page app installed
|
||||
// @Description 分页获取已安装应用列表
|
||||
// @Accept json
|
||||
// @Param request body request.AppInstalledSearch true "request"
|
||||
// @Success 200
|
||||
@@ -47,21 +46,41 @@ 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 key path string true "request"
|
||||
// @Param request body request.AppInstalledInfo true "request"
|
||||
// @Success 200 {object} response.AppInstalledCheck
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /apps/installed/check/:key [get]
|
||||
// @Router /apps/installed/check [post]
|
||||
func (b *BaseApi) CheckAppInstalled(c *gin.Context) {
|
||||
key, ok := c.Params.Get("key")
|
||||
if !ok {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
|
||||
var req request.AppInstalledInfo
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
checkData, err := appInstallService.CheckExist(key)
|
||||
if err := global.VALID.Struct(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
checkData, err := appInstallService.CheckExist(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -73,17 +92,17 @@ func (b *BaseApi) CheckAppInstalled(c *gin.Context) {
|
||||
// @Summary Search app port by key
|
||||
// @Description 获取应用端口
|
||||
// @Accept json
|
||||
// @Param key path string true "request"
|
||||
// @Param request body dto.OperationWithNameAndType true "request"
|
||||
// @Success 200 {integer} port
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /apps/installed/loadport/:key [get]
|
||||
// @Router /apps/installed/loadport [post]
|
||||
func (b *BaseApi) LoadPort(c *gin.Context) {
|
||||
key, ok := c.Params.Get("key")
|
||||
if !ok {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
|
||||
var req dto.OperationWithNameAndType
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
port, err := appInstallService.LoadPort(key)
|
||||
port, err := appInstallService.LoadPort(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -95,17 +114,17 @@ func (b *BaseApi) LoadPort(c *gin.Context) {
|
||||
// @Summary Search app password by key
|
||||
// @Description 获取应用连接信息
|
||||
// @Accept json
|
||||
// @Param key path string true "request"
|
||||
// @Param request body dto.OperationWithNameAndType true "request"
|
||||
// @Success 200 {string} response.DatabaseConn
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /apps/installed/conninfo/:key [get]
|
||||
func (b *BaseApi) LoadConnInfo(c *gin.Context) {
|
||||
key, ok := c.Params.Get("key")
|
||||
if !ok {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
|
||||
var req dto.OperationWithNameAndType
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
conn, err := appInstallService.LoadConnInfo(key)
|
||||
conn, err := appInstallService.LoadConnInfo(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -243,17 +262,17 @@ func (b *BaseApi) ChangeAppPort(c *gin.Context) {
|
||||
// @Summary Search default config by key
|
||||
// @Description 通过 key 获取应用默认配置
|
||||
// @Accept json
|
||||
// @Param key path string true "request"
|
||||
// @Param request body dto.OperationWithNameAndType true "request"
|
||||
// @Success 200 {string} content
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /apps/installed/conf/:key [get]
|
||||
// @Router /apps/installed/conf [post]
|
||||
func (b *BaseApi) GetDefaultConfig(c *gin.Context) {
|
||||
key := c.Param("key")
|
||||
if key == "" {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||
var req dto.OperationWithNameAndType
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
content, err := appInstallService.GetDefaultConfigByKey(key)
|
||||
content, err := appInstallService.GetDefaultConfigByKey(req.Type, req.Name)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
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"
|
||||
@@ -20,6 +22,7 @@ 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 {
|
||||
@@ -32,8 +35,13 @@ 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)
|
||||
user, err := authService.Login(c, req, string(entrance))
|
||||
go saveLoginLogs(c, err)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
@@ -49,6 +57,7 @@ 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 {
|
||||
@@ -59,8 +68,13 @@ 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)
|
||||
user, err := authService.MFALogin(c, req, string(entrance))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
@@ -335,7 +335,7 @@ func (b *BaseApi) Backup(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
case "mysql":
|
||||
case "mysql", "mariadb":
|
||||
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":
|
||||
case "mysql", "mariadb":
|
||||
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":
|
||||
case "mysql", "mariadb":
|
||||
if err := backupService.MysqlRecoverByUpload(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
@@ -9,16 +9,16 @@ import (
|
||||
)
|
||||
|
||||
// @Tags Database
|
||||
// @Summary Create remote database
|
||||
// @Summary Create database
|
||||
// @Description 创建远程数据库
|
||||
// @Accept json
|
||||
// @Param request body dto.RemoteDBCreate true "request"
|
||||
// @Param request body dto.DatabaseCreate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @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
|
||||
// @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
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
@@ -27,7 +27,7 @@ func (b *BaseApi) CreateRemoteDB(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := remoteDBService.Create(req); err != nil {
|
||||
if err := databaseService.Create(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
@@ -35,16 +35,16 @@ func (b *BaseApi) CreateRemoteDB(c *gin.Context) {
|
||||
}
|
||||
|
||||
// @Tags Database
|
||||
// @Summary Check remote database
|
||||
// @Summary Check database
|
||||
// @Description 检测远程数据库连接性
|
||||
// @Accept json
|
||||
// @Param request body dto.RemoteDBCreate true "request"
|
||||
// @Param request body dto.DatabaseCreate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @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
|
||||
// @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
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
@@ -53,25 +53,25 @@ func (b *BaseApi) CheckeRemoteDB(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, remoteDBService.CheckeRemoteDB(req))
|
||||
helper.SuccessWithData(c, databaseService.CheckDatabase(req))
|
||||
}
|
||||
|
||||
// @Tags Database
|
||||
// @Summary Page remote databases
|
||||
// @Summary Page databases
|
||||
// @Description 获取远程数据库列表分页
|
||||
// @Accept json
|
||||
// @Param request body dto.RemoteDBSearch true "request"
|
||||
// @Param request body dto.DatabaseSearch true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/remote/search [post]
|
||||
func (b *BaseApi) SearchRemoteDB(c *gin.Context) {
|
||||
var req dto.RemoteDBSearch
|
||||
// @Router /databases/db/search [post]
|
||||
func (b *BaseApi) SearchDatabase(c *gin.Context) {
|
||||
var req dto.DatabaseSearch
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
total, list, err := remoteDBService.SearchWithPage(req)
|
||||
total, list, err := databaseService.SearchWithPage(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -84,18 +84,18 @@ func (b *BaseApi) SearchRemoteDB(c *gin.Context) {
|
||||
}
|
||||
|
||||
// @Tags Database
|
||||
// @Summary List remote databases
|
||||
// @Summary List databases
|
||||
// @Description 获取远程数据库列表
|
||||
// @Success 200 {array} dto.RemoteDBOption
|
||||
// @Success 200 {array} dto.DatabaseOption
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/remote/list/:type [get]
|
||||
func (b *BaseApi) ListRemoteDB(c *gin.Context) {
|
||||
// @Router /databases/db/list/:type [get]
|
||||
func (b *BaseApi) ListDatabase(c *gin.Context) {
|
||||
dbType, err := helper.GetStrParamByKey(c, "type")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
list, err := remoteDBService.List(dbType)
|
||||
list, err := databaseService.List(dbType)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -105,18 +105,18 @@ func (b *BaseApi) ListRemoteDB(c *gin.Context) {
|
||||
}
|
||||
|
||||
// @Tags Database
|
||||
// @Summary Get remote databases
|
||||
// @Summary Get databases
|
||||
// @Description 获取远程数据库
|
||||
// @Success 200 {object} dto.RemoteDBInfo
|
||||
// @Success 200 {object} dto.DatabaseInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/remote/:name [get]
|
||||
func (b *BaseApi) GetRemoteDB(c *gin.Context) {
|
||||
// @Router /databases/db/:name [get]
|
||||
func (b *BaseApi) GetDatabase(c *gin.Context) {
|
||||
name, err := helper.GetStrParamByKey(c, "name")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
data, err := remoteDBService.Get(name)
|
||||
data, err := databaseService.Get(name)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -126,15 +126,15 @@ func (b *BaseApi) GetRemoteDB(c *gin.Context) {
|
||||
}
|
||||
|
||||
// @Tags Database
|
||||
// @Summary Delete remote database
|
||||
// @Summary Delete database
|
||||
// @Description 删除远程数据库
|
||||
// @Accept json
|
||||
// @Param request body dto.OperateByID true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @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) {
|
||||
// @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) {
|
||||
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) DeleteRemoteDB(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := remoteDBService.Delete(req.ID); err != nil {
|
||||
if err := databaseService.Delete(req.ID); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
@@ -153,16 +153,16 @@ func (b *BaseApi) DeleteRemoteDB(c *gin.Context) {
|
||||
}
|
||||
|
||||
// @Tags Database
|
||||
// @Summary Update remote database
|
||||
// @Summary Update database
|
||||
// @Description 更新远程数据库
|
||||
// @Accept json
|
||||
// @Param request body dto.RemoteDBUpdate true "request"
|
||||
// @Param request body dto.DatabaseUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @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
|
||||
// @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
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
@@ -172,7 +172,7 @@ func (b *BaseApi) UpdateRemoteDB(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := remoteDBService.Update(req); err != nil {
|
||||
if err := databaseService.Update(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
@@ -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,15 +232,21 @@ 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/:from [get]
|
||||
// @Router /databases/load [post]
|
||||
func (b *BaseApi) LoadDBFromRemote(c *gin.Context) {
|
||||
from, err := helper.GetStrParamByKey(c, "from")
|
||||
if err != nil {
|
||||
var req dto.MysqlLoadDB
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := mysqlService.LoadFromRemote(from); err != nil {
|
||||
if err := global.VALID.Struct(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := mysqlService.LoadFromRemote(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
@@ -252,12 +258,12 @@ func (b *BaseApi) LoadDBFromRemote(c *gin.Context) {
|
||||
// @Summary Check before delete mysql database
|
||||
// @Description Mysql 数据库删除前检查
|
||||
// @Accept json
|
||||
// @Param request body dto.OperateByID true "request"
|
||||
// @Param request body dto.MysqlDBDeleteCheck true "request"
|
||||
// @Success 200 {array} string
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/del/check [post]
|
||||
func (b *BaseApi) DeleteCheckMysql(c *gin.Context) {
|
||||
var req dto.OperateByID
|
||||
var req dto.MysqlDBDeleteCheck
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
@@ -267,7 +273,7 @@ func (b *BaseApi) DeleteCheckMysql(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
apps, err := mysqlService.DeleteCheck(req.ID)
|
||||
apps, err := mysqlService.DeleteCheck(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -308,11 +314,18 @@ 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 [get]
|
||||
// @Router /databases/baseinfo [post]
|
||||
func (b *BaseApi) LoadBaseinfo(c *gin.Context) {
|
||||
data, err := mysqlService.LoadBaseInfo()
|
||||
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)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -346,11 +359,18 @@ 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 [get]
|
||||
// @Router /databases/remote [post]
|
||||
func (b *BaseApi) LoadRemoteAccess(c *gin.Context) {
|
||||
isRemote, err := mysqlService.LoadRemoteAccess()
|
||||
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)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -362,11 +382,18 @@ 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 [get]
|
||||
// @Router /databases/status [post]
|
||||
func (b *BaseApi) LoadStatus(c *gin.Context) {
|
||||
data, err := mysqlService.LoadStatus()
|
||||
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)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -378,11 +405,18 @@ 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 [get]
|
||||
// @Router /databases/variables [post]
|
||||
func (b *BaseApi) LoadVariables(c *gin.Context) {
|
||||
data, err := mysqlService.LoadVariables()
|
||||
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)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
@@ -92,13 +92,13 @@ func (b *BaseApi) UpdateRedisConf(c *gin.Context) {
|
||||
// @Summary Change redis password
|
||||
// @Description 更新 redis 密码
|
||||
// @Accept json
|
||||
// @Param request body dto.ChangeDBInfo true "request"
|
||||
// @Param request body dto.ChangeRedisPass 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.ChangeDBInfo
|
||||
var req dto.ChangeRedisPass
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
|
||||
@@ -22,7 +22,7 @@ var (
|
||||
dockerService = service.NewIDockerService()
|
||||
|
||||
mysqlService = service.NewIMysqlService()
|
||||
remoteDBService = service.NewIRemoteDBService()
|
||||
databaseService = service.NewIDatabaseService()
|
||||
redisService = service.NewIRedisService()
|
||||
|
||||
cronjobService = service.NewICronjobService()
|
||||
|
||||
@@ -38,6 +38,10 @@ 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 {
|
||||
@@ -156,6 +160,31 @@ 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 更新端口防火墙规则
|
||||
|
||||
@@ -189,16 +189,6 @@ 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) {
|
||||
helper.SuccessWithData(c, hostToolService.LoadProcessStatus())
|
||||
}
|
||||
|
||||
// @Tags Host tool
|
||||
// @Summary Get Supervisor process config
|
||||
// @Description 操作 Supervisor 进程文件
|
||||
|
||||
@@ -60,6 +60,32 @@ 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 更新快照描述信息
|
||||
|
||||
@@ -912,3 +912,25 @@ 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)
|
||||
}
|
||||
|
||||
@@ -67,7 +67,8 @@ type LocalAppInstallDefine struct {
|
||||
}
|
||||
|
||||
type ExtraProperties struct {
|
||||
Tags []Tag `json:"tags"`
|
||||
Tags []Tag `json:"tags"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type AppProperty struct {
|
||||
@@ -132,3 +133,9 @@ 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"`
|
||||
}
|
||||
|
||||
@@ -21,25 +21,18 @@ 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 redis website"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb 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 redis website"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
File string `json:"file"`
|
||||
|
||||
@@ -24,7 +24,8 @@ type ContainerInfo struct {
|
||||
State string `json:"state"`
|
||||
RunTime string `json:"runTime"`
|
||||
|
||||
Ports []string `json:"ports"`
|
||||
Network []string `json:"network"`
|
||||
Ports []string `json:"ports"`
|
||||
|
||||
IsFromApp bool `json:"isFromApp"`
|
||||
IsFromCompose bool `json:"isFromCompose"`
|
||||
@@ -44,6 +45,7 @@ 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"`
|
||||
|
||||
@@ -14,6 +14,7 @@ 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"`
|
||||
@@ -36,6 +37,7 @@ 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"`
|
||||
@@ -79,6 +81,7 @@ 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"`
|
||||
|
||||
+101
-39
@@ -4,10 +4,10 @@ import "time"
|
||||
|
||||
type MysqlDBSearch struct {
|
||||
PageInfo
|
||||
Info string `json:"info"`
|
||||
From string `json:"from"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
Info string `json:"info"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
OrderBy string `json:"orderBy"`
|
||||
Order string `json:"order"`
|
||||
}
|
||||
|
||||
type MysqlDBInfo struct {
|
||||
@@ -25,14 +25,17 @@ type MysqlDBInfo struct {
|
||||
}
|
||||
|
||||
type MysqlOption struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
From string `json:"from"`
|
||||
ID uint `json:"id"`
|
||||
From string `json:"from"`
|
||||
Type string `json:"type"`
|
||||
Database string `json:"database"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type MysqlDBCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
From string `json:"from" validate:"required"`
|
||||
From string `json:"from" validate:"required,oneof=local remote"`
|
||||
Database string `json:"database" 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"`
|
||||
@@ -40,10 +43,24 @@ 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"`
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
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"`
|
||||
}
|
||||
|
||||
type MysqlStatus struct {
|
||||
@@ -107,18 +124,27 @@ 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 {
|
||||
MysqlName string `json:"mysqlName" validate:"required"`
|
||||
File string `json:"file"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
type ChangeDBInfo struct {
|
||||
ID uint `json:"id"`
|
||||
From string `json:"from"`
|
||||
Value string `json:"value" validate:"required"`
|
||||
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"`
|
||||
}
|
||||
|
||||
type DBBaseInfo struct {
|
||||
@@ -127,30 +153,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"`
|
||||
}
|
||||
|
||||
type RecoverDB struct {
|
||||
MysqlName string `json:"mysqlName" validate:"required"`
|
||||
DBName string `json:"dbName" validate:"required"`
|
||||
BackupName string `json:"backupName" validate:"required"`
|
||||
}
|
||||
|
||||
type UploadRecover struct {
|
||||
MysqlName string `json:"mysqlName" validate:"required"`
|
||||
DBName string `json:"dbName" validate:"required"`
|
||||
FileName string `json:"fileName"`
|
||||
FileDir string `json:"fileDir"`
|
||||
}
|
||||
|
||||
// redis
|
||||
type ChangeRedisPass struct {
|
||||
Value string `json:"value" validate:"required"`
|
||||
}
|
||||
|
||||
type RedisConfUpdate struct {
|
||||
Timeout string `json:"timeout"`
|
||||
Maxclients string `json:"maxclients"`
|
||||
@@ -209,3 +216,58 @@ 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"`
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ type FirewallBaseInfo struct {
|
||||
|
||||
type RuleSearch struct {
|
||||
PageInfo
|
||||
Info string `json:"info"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
Info string `json:"info"`
|
||||
Status string `json:"status"`
|
||||
Strategy string `json:"strategy"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
}
|
||||
|
||||
type FirewallOperation struct {
|
||||
@@ -23,12 +25,26 @@ 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 {
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
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"`
|
||||
}
|
||||
@@ -41,6 +41,11 @@ 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"`
|
||||
|
||||
@@ -17,6 +17,7 @@ type RuntimeCreate struct {
|
||||
Image string `json:"image"`
|
||||
Type string `json:"type"`
|
||||
Version string `json:"version"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
type RuntimeDelete struct {
|
||||
@@ -29,4 +30,6 @@ type RuntimeUpdate struct {
|
||||
Params map[string]interface{} `json:"params"`
|
||||
Image string `json:"image"`
|
||||
Version string `json:"version"`
|
||||
Rebuild bool `json:"rebuild"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
@@ -141,9 +141,11 @@ type WebsiteNginxUpdate struct {
|
||||
}
|
||||
|
||||
type WebsiteLogReq struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Operate string `json:"operate" validate:"required"`
|
||||
LogType string `json:"logType" validate:"required"`
|
||||
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"`
|
||||
}
|
||||
|
||||
type WebsiteDefaultUpdate struct {
|
||||
@@ -211,3 +213,7 @@ 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"`
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ 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 {
|
||||
|
||||
@@ -6,4 +6,5 @@ type RuntimeRes struct {
|
||||
model.Runtime
|
||||
AppParams []AppParam `json:"appParams"`
|
||||
AppID uint `json:"appId"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ type WebsiteHTTPS struct {
|
||||
type WebsiteLog struct {
|
||||
Enable bool `json:"enable"`
|
||||
Content string `json:"content"`
|
||||
End bool `json:"end"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type PHPConfig struct {
|
||||
@@ -52,3 +54,10 @@ 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"`
|
||||
}
|
||||
|
||||
@@ -75,7 +75,21 @@ 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,4 +6,5 @@ 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"`
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ 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"`
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
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);"`
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
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"`
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
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);"`
|
||||
}
|
||||
@@ -17,3 +17,18 @@ 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"`
|
||||
}
|
||||
|
||||
@@ -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.Debug().Limit(size).Offset(size * (page - 1)).Preload("AppTags").Find(&apps).Error
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Preload("AppTags").Find(&apps).Error
|
||||
return count, apps, err
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package repo
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
@@ -160,6 +161,7 @@ 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"`
|
||||
@@ -193,7 +195,7 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
|
||||
return nil, err
|
||||
}
|
||||
switch app.Key {
|
||||
case "mysql":
|
||||
case "mysql", "mariadb":
|
||||
password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string)
|
||||
if ok {
|
||||
info.Password = password
|
||||
@@ -203,6 +205,15 @@ 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)
|
||||
@@ -218,5 +229,6 @@ 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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
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
|
||||
}
|
||||
@@ -2,9 +2,11 @@ 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"
|
||||
)
|
||||
|
||||
@@ -19,7 +21,6 @@ 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
|
||||
}
|
||||
|
||||
@@ -33,33 +34,64 @@ func (u *MysqlRepo) Get(opts ...DBOption) (model.DatabaseMysql, error) {
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.First(&mysql).Error
|
||||
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
|
||||
return mysql, err
|
||||
}
|
||||
|
||||
func (u *MysqlRepo) List(opts ...DBOption) ([]model.DatabaseMysql, error) {
|
||||
var users []model.DatabaseMysql
|
||||
var mysqls []model.DatabaseMysql
|
||||
db := global.DB.Model(&model.DatabaseMysql{})
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.Find(&users).Error
|
||||
return users, err
|
||||
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
|
||||
}
|
||||
|
||||
func (u *MysqlRepo) Page(page, size int, opts ...DBOption) (int64, []model.DatabaseMysql, error) {
|
||||
var users []model.DatabaseMysql
|
||||
var mysqls []model.DatabaseMysql
|
||||
db := global.DB.Model(&model.DatabaseMysql{})
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -75,13 +107,6 @@ 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)
|
||||
|
||||
@@ -19,6 +19,12 @@ 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 {
|
||||
@@ -106,3 +112,48 @@ 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
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -2,7 +2,9 @@ package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -20,6 +22,7 @@ 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 {
|
||||
@@ -65,6 +68,16 @@ 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
|
||||
|
||||
@@ -12,6 +12,12 @@ 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 {
|
||||
@@ -67,3 +73,33 @@ 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
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ 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 {
|
||||
@@ -131,3 +132,7 @@ 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
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ 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 {
|
||||
@@ -85,3 +86,7 @@ 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
|
||||
}
|
||||
|
||||
+62
-22
@@ -5,6 +5,14 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
@@ -19,12 +27,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
http2 "github.com/1Panel-dev/1Panel/backend/utils/http"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AppService struct {
|
||||
@@ -274,6 +276,20 @@ 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
|
||||
@@ -291,14 +307,6 @@ 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
|
||||
}
|
||||
@@ -352,13 +360,20 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
appInstall.ContainerName = containerName
|
||||
|
||||
index := 0
|
||||
serviceName := ""
|
||||
for k := range servicesMap {
|
||||
appInstall.ServiceName = k
|
||||
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
|
||||
@@ -382,6 +397,14 @@ 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
|
||||
@@ -394,15 +417,17 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
if err = copyData(app, appDetail, appInstall, req); err != nil {
|
||||
if appInstall.Status == constant.Installing {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
appInstall.Status = constant.Error
|
||||
appInstall.Message = err.Error()
|
||||
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||
}
|
||||
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||
}()
|
||||
if err = copyData(app, appDetail, appInstall, req); err != nil {
|
||||
return
|
||||
}
|
||||
if err = upAppPre(app, appInstall); err != nil {
|
||||
if err = runScript(appInstall, "init"); err != nil {
|
||||
return
|
||||
}
|
||||
upApp(appInstall)
|
||||
@@ -668,6 +693,21 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
||||
res.CanUpdate = true
|
||||
return res, err
|
||||
}
|
||||
if err = getAppFromRepo(fmt.Sprintf("%s/%s/1panel.json.zip", global.CONF.System.AppRepo, global.CONF.System.Mode)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
listFile := path.Join(constant.ResourceDir, "1panel.json")
|
||||
content, err := os.ReadFile(listFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := &dto.AppList{}
|
||||
if err = json.Unmarshal(content, list); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if list.Extra.Version != "" && setting.SystemVersion != list.Extra.Version && !common.CompareVersion(setting.SystemVersion, list.Extra.Version) {
|
||||
return nil, buserr.New("ErrVersionTooLow")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -765,8 +805,8 @@ func (a AppService) SyncAppListFromRemote() (err error) {
|
||||
for _, v := range versions {
|
||||
version := v.Name
|
||||
detail := detailsMap[version]
|
||||
|
||||
dockerComposeUrl := fmt.Sprintf("%s/%s/%s/%s", baseRemoteUrl, app.Key, version, "docker-compose.yml")
|
||||
versionUrl := fmt.Sprintf("%s/%s/%s", baseRemoteUrl, app.Key, version)
|
||||
dockerComposeUrl := fmt.Sprintf("%s/%s", versionUrl, "docker-compose.yml")
|
||||
composeRes, err := http.Get(dockerComposeUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -779,7 +819,7 @@ func (a AppService) SyncAppListFromRemote() (err error) {
|
||||
|
||||
paramByte, _ := json.Marshal(v.AppForm)
|
||||
detail.Params = string(paramByte)
|
||||
detail.DownloadUrl = v.DownloadUrl
|
||||
detail.DownloadUrl = fmt.Sprintf("%s/%s", versionUrl, app.Key+"-"+version+".tar.gz")
|
||||
detail.DownloadCallBackUrl = v.DownloadCallBackUrl
|
||||
detail.Update = true
|
||||
detail.LastModified = v.LastModified
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
@@ -12,6 +11,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
@@ -40,9 +41,9 @@ type AppInstallService struct {
|
||||
|
||||
type IAppInstallService interface {
|
||||
Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error)
|
||||
CheckExist(key string) (*response.AppInstalledCheck, error)
|
||||
LoadPort(key string) (int64, error)
|
||||
LoadConnInfo(key string) (response.DatabaseConn, error)
|
||||
CheckExist(req request.AppInstalledInfo) (*response.AppInstalledCheck, error)
|
||||
LoadPort(req dto.OperationWithNameAndType) (int64, error)
|
||||
LoadConnInfo(req dto.OperationWithNameAndType) (response.DatabaseConn, error)
|
||||
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error)
|
||||
Operate(req request.AppInstalledOperate) error
|
||||
Update(req request.AppInstalledUpdate) error
|
||||
@@ -52,14 +53,28 @@ type IAppInstallService interface {
|
||||
GetUpdateVersions(installId uint) ([]dto.AppVersion, error)
|
||||
GetParams(id uint) (*response.AppConfig, error)
|
||||
ChangeAppPort(req request.PortUpdate) error
|
||||
GetDefaultConfigByKey(key string) (string, error)
|
||||
GetDefaultConfigByKey(key, name 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
|
||||
@@ -115,23 +130,30 @@ func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []respo
|
||||
return total, installDTOs, nil
|
||||
}
|
||||
|
||||
func (a *AppInstallService) CheckExist(key string) (*response.AppInstalledCheck, error) {
|
||||
func (a *AppInstallService) CheckExist(req request.AppInstalledInfo) (*response.AppInstalledCheck, error) {
|
||||
res := &response.AppInstalledCheck{
|
||||
IsExist: false,
|
||||
}
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(key))
|
||||
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(req.Key))
|
||||
if err != nil {
|
||||
return res, nil
|
||||
}
|
||||
res.App = app.Name
|
||||
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithAppId(app.ID))
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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
|
||||
@@ -140,22 +162,24 @@ func (a *AppInstallService) CheckExist(key string) (*response.AppInstalledCheck,
|
||||
res.Status = appInstall.Status
|
||||
res.AppInstallID = appInstall.ID
|
||||
res.IsExist = true
|
||||
res.InstallPath = path.Join(constant.AppInstallDir, app.Key, appInstall.Name)
|
||||
res.InstallPath = path.Join(constant.AppInstallDir, appInstall.App.Key, appInstall.Name)
|
||||
res.HttpPort = appInstall.HttpPort
|
||||
res.HttpsPort = appInstall.HttpsPort
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a *AppInstallService) LoadPort(key string) (int64, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo(key, "")
|
||||
func (a *AppInstallService) LoadPort(req dto.OperationWithNameAndType) (int64, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return int64(0), nil
|
||||
}
|
||||
return app.Port, nil
|
||||
}
|
||||
|
||||
func (a *AppInstallService) LoadConnInfo(key string) (response.DatabaseConn, error) {
|
||||
func (a *AppInstallService) LoadConnInfo(req dto.OperationWithNameAndType) (response.DatabaseConn, error) {
|
||||
var data response.DatabaseConn
|
||||
app, err := appInstallRepo.LoadBaseInfo(key, "")
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return data, nil
|
||||
}
|
||||
@@ -215,26 +239,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:
|
||||
@@ -393,7 +417,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())
|
||||
}
|
||||
}
|
||||
@@ -402,25 +426,50 @@ 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
|
||||
for _, install := range installs {
|
||||
paramMap := make(map[string]string)
|
||||
if install.Param != "" {
|
||||
_ = json.Unmarshal([]byte(install.Param), ¶mMap)
|
||||
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), ¶mMap)
|
||||
}
|
||||
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), ¶mMap)
|
||||
}
|
||||
res = append(res, response.AppService{
|
||||
Label: install.Name,
|
||||
Value: install.ServiceName,
|
||||
Config: paramMap,
|
||||
})
|
||||
}
|
||||
res = append(res, response.AppService{
|
||||
Label: install.Name,
|
||||
Value: install.ServiceName,
|
||||
Config: paramMap,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
@@ -523,22 +572,22 @@ func (a *AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, erro
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a *AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
|
||||
appInstall, err := getAppInstallByKey(key)
|
||||
func (a *AppInstallService) GetDefaultConfigByKey(key, name string) (string, error) {
|
||||
baseInfo, err := appInstallRepo.LoadBaseInfo(key, name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
filePath := path.Join(constant.AppResourceDir, "remote", appInstall.App.Key, appInstall.Version, "conf")
|
||||
filePath := path.Join(constant.AppResourceDir, "remote", baseInfo.Key, baseInfo.Version, "conf")
|
||||
if !fileOp.Stat(filePath) {
|
||||
filePath = path.Join(constant.AppResourceDir, appInstall.App.Key, "versions", appInstall.Version, "conf")
|
||||
filePath = path.Join(constant.AppResourceDir, baseInfo.Key, "versions", baseInfo.Version, "conf")
|
||||
}
|
||||
if !fileOp.Stat(filePath) {
|
||||
return "", buserr.New(constant.ErrPathNotFound)
|
||||
}
|
||||
|
||||
if key == constant.AppMysql {
|
||||
if key == constant.AppMysql || key == constant.AppMariaDB {
|
||||
filePath = path.Join(filePath, "my.cnf")
|
||||
}
|
||||
if key == constant.AppRedis {
|
||||
@@ -626,8 +675,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
|
||||
}
|
||||
@@ -731,7 +780,7 @@ func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value
|
||||
envKey := ""
|
||||
switch param {
|
||||
case "password":
|
||||
if appKey == "mysql" {
|
||||
if appKey == "mysql" || appKey == "mariadb" {
|
||||
envKey = "PANEL_DB_ROOT_PASSWORD="
|
||||
} else {
|
||||
envKey = "PANEL_REDIS_ROOT_PASSWORD="
|
||||
|
||||
@@ -15,6 +15,8 @@ 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"
|
||||
@@ -80,11 +82,48 @@ 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" {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
switch app.Key {
|
||||
case "mysql", "mariadb", "postgresql":
|
||||
case "mysql", "mariadb", "postgresql", "mongodb":
|
||||
if password, ok := params["PANEL_DB_ROOT_PASSWORD"]; ok {
|
||||
if password != "" {
|
||||
authParam := dto.AuthParam{
|
||||
@@ -95,6 +134,13 @@ 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":
|
||||
@@ -109,8 +155,12 @@ 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)
|
||||
@@ -140,6 +190,7 @@ 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
|
||||
@@ -173,7 +224,7 @@ func handleAppInstallErr(ctx context.Context, install *model.AppInstall) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := deleteLink(ctx, install, true, true); err != nil {
|
||||
if err := deleteLink(ctx, install, true, true, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -188,20 +239,33 @@ 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); err != nil && !forceDelete {
|
||||
if err := deleteLink(ctx, &install, deleteDB, forceDelete, deleteBackup); err != nil && !forceDelete {
|
||||
return err
|
||||
}
|
||||
_ = 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)
|
||||
|
||||
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))
|
||||
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)
|
||||
@@ -219,21 +283,25 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, forceDelete bool) error {
|
||||
func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, forceDelete bool, deleteBackup bool) error {
|
||||
|
||||
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
if len(resources) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, re := range resources {
|
||||
mysqlService := NewIMysqlService()
|
||||
if re.Key == "mysql" && deleteDB {
|
||||
if (re.Key == constant.AppMysql || re.Key == constant.AppMariaDB) && 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,
|
||||
ID: database.ID,
|
||||
ForceDelete: forceDelete,
|
||||
DeleteBackup: deleteBackup,
|
||||
Type: re.Key,
|
||||
Database: database.MysqlName,
|
||||
}); err != nil && !forceDelete {
|
||||
return err
|
||||
}
|
||||
@@ -284,10 +352,19 @@ func upgradeInstall(installId uint, detailId uint, backup bool) error {
|
||||
detailDir = path.Join(constant.ResourceDir, "apps", "local", strings.TrimPrefix(install.App.Key, "local"), detail.Version)
|
||||
}
|
||||
|
||||
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
|
||||
stdout, _ := cmd.CombinedOutput()
|
||||
command := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
|
||||
stdout, _ := command.CombinedOutput()
|
||||
if stdout != nil {
|
||||
global.LOG.Errorf("upgrade app [%s] [%s] cp file log : %s ", install.App.Key, install.Name, string(stdout))
|
||||
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()
|
||||
}
|
||||
|
||||
composeMap := make(map[string]interface{})
|
||||
@@ -300,20 +377,21 @@ func upgradeInstall(installId uint, detailId uint, backup bool) error {
|
||||
return
|
||||
}
|
||||
servicesMap := value.(map[string]interface{})
|
||||
index := 0
|
||||
oldServiceName := ""
|
||||
for k := range servicesMap {
|
||||
oldServiceName = k
|
||||
index++
|
||||
if index > 0 {
|
||||
break
|
||||
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)
|
||||
}
|
||||
}
|
||||
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
|
||||
@@ -366,12 +444,16 @@ 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
|
||||
}
|
||||
@@ -475,6 +557,8 @@ 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)
|
||||
}
|
||||
@@ -496,7 +580,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, appDetail.Version+".tar.gz")
|
||||
filePath := path.Join(appVersionDir, app.Key+"-"+appDetail.Version+".tar.gz")
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
@@ -511,7 +595,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, appVersionDir, files.TarGz); err != nil {
|
||||
if err = fileOp.Decompress(filePath, appResourceDir, files.TarGz); err != nil {
|
||||
global.LOG.Errorf("decompress app[%s] error %v", app.Name, err)
|
||||
return
|
||||
}
|
||||
@@ -574,17 +658,28 @@ func copyData(app model.App, appDetail model.AppDetail, appInstall *model.AppIns
|
||||
return
|
||||
}
|
||||
|
||||
// 处理文件夹权限等问题
|
||||
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)
|
||||
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
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -660,16 +755,24 @@ func upApp(appInstall *model.AppInstall) {
|
||||
}
|
||||
|
||||
func rebuildApp(appInstall model.AppInstall) error {
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
||||
func getAppDetails(details []model.AppDetail, versions []dto.AppConfigVersion) map[string]model.AppDetail {
|
||||
@@ -840,6 +943,10 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]respons
|
||||
}
|
||||
versions = common.GetSortedVersions(versions)
|
||||
if len(versions) == 0 {
|
||||
if !updated {
|
||||
installDTO.CanUpdate = false
|
||||
res = append(res, installDTO)
|
||||
}
|
||||
continue
|
||||
}
|
||||
lastVersion := versions[0]
|
||||
@@ -871,6 +978,16 @@ 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 {
|
||||
|
||||
@@ -4,6 +4,7 @@ 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"
|
||||
@@ -19,16 +20,16 @@ type AuthService struct{}
|
||||
type IAuthService interface {
|
||||
CheckIsSafety(code string) (string, error)
|
||||
VerifyCode(code string) (bool, error)
|
||||
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error)
|
||||
Login(c *gin.Context, info dto.Login, entrance string) (*dto.UserLoginInfo, error)
|
||||
LogOut(c *gin.Context) error
|
||||
MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLoginInfo, error)
|
||||
MFALogin(c *gin.Context, info dto.MFALogin, entrance string) (*dto.UserLoginInfo, error)
|
||||
}
|
||||
|
||||
func NewIAuthService() IAuthService {
|
||||
return &AuthService{}
|
||||
}
|
||||
|
||||
func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error) {
|
||||
func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*dto.UserLoginInfo, error) {
|
||||
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
||||
@@ -44,6 +45,13 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo,
|
||||
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
|
||||
@@ -57,7 +65,7 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo,
|
||||
return u.generateSession(c, info.Name, info.AuthMethod)
|
||||
}
|
||||
|
||||
func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLoginInfo, error) {
|
||||
func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance string) (*dto.UserLoginInfo, error) {
|
||||
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
||||
@@ -73,7 +81,13 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLogi
|
||||
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
|
||||
|
||||
@@ -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" {
|
||||
if resource.Key == "mysql" || resource.Key == "mariadb" {
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -173,8 +173,15 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
newEnvFile := ""
|
||||
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
for _, resource := range resources {
|
||||
if resource.Key == "mysql" {
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfo(resource.Key, "")
|
||||
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 err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -183,7 +190,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
return err
|
||||
}
|
||||
|
||||
newDB, envMap, err := reCreateDB(db.ID, oldInstall.Env)
|
||||
newDB, envMap, err := reCreateDB(db.ID, resourceApp, oldInstall.Env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -245,10 +252,10 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
return nil
|
||||
}
|
||||
|
||||
func reCreateDB(dbID uint, oldEnv string) (*model.DatabaseMysql, map[string]interface{}, error) {
|
||||
func reCreateDB(dbID uint, app model.AppInstall, oldEnv string) (*model.DatabaseMysql, map[string]interface{}, error) {
|
||||
mysqlService := NewIMysqlService()
|
||||
ctx := context.Background()
|
||||
_ = mysqlService.Delete(ctx, dto.MysqlDBDelete{ID: dbID, DeleteBackup: true, ForceDelete: true})
|
||||
_ = mysqlService.Delete(ctx, dto.MysqlDBDelete{ID: dbID, Database: app.Name, Type: app.App.Key, DeleteBackup: false, ForceDelete: true})
|
||||
|
||||
envMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(oldEnv), &envMap); err != nil {
|
||||
@@ -260,6 +267,7 @@ func reCreateDB(dbID uint, oldEnv string) (*model.DatabaseMysql, map[string]inte
|
||||
createDB, err := mysqlService.Create(context.Background(), dto.MysqlDBCreate{
|
||||
Name: oldName,
|
||||
From: "local",
|
||||
Database: app.Name,
|
||||
Format: "utf8mb4",
|
||||
Username: oldUser,
|
||||
Password: oldPassword,
|
||||
|
||||
@@ -23,7 +23,7 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
|
||||
}
|
||||
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
targetDir := path.Join(localDir, fmt.Sprintf("database/mysql/%s/%s", req.Name, req.DetailName))
|
||||
targetDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", req.Type, 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: "mysql",
|
||||
Type: req.Type,
|
||||
Name: req.Name,
|
||||
DetailName: req.DetailName,
|
||||
Source: "LOCAL",
|
||||
@@ -97,12 +97,12 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleMysqlBackup(name, dbName, targetDir, fileName string) error {
|
||||
dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(dbName), mysqlRepo.WithByMysqlName(name))
|
||||
func handleMysqlBackup(database, dbName, targetDir, fileName string) error {
|
||||
dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(dbName), mysqlRepo.WithByMysqlName(database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli, _, err := LoadMysqlClientByFrom(dbInfo.From)
|
||||
cli, _, err := LoadMysqlClientByFrom(database)
|
||||
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(dbInfo.From)
|
||||
cli, _, err := LoadMysqlClientByFrom(req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/mysql/%s_%s.sql.gz", req.DetailName, time.Now().Format("20060102150405")))
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format("20060102150405")))
|
||||
if err := cli.Backup(client.BackupInfo{
|
||||
Name: req.DetailName,
|
||||
Format: dbInfo.Format,
|
||||
|
||||
@@ -147,14 +147,7 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
IsFromApp = true
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
ports := simplifyPort(item.Ports)
|
||||
backDatas[i] = dto.ContainerInfo{
|
||||
ContainerID: item.ID,
|
||||
CreateTime: time.Unix(item.Created, 0).Format("2006-01-02 15:04:05"),
|
||||
@@ -167,6 +160,14 @@ 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
|
||||
@@ -365,6 +366,7 @@ 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 {
|
||||
@@ -531,11 +533,15 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
container, err := client.ContainerInspect(context.Background(), req.Name)
|
||||
ctx := context.Background()
|
||||
containerItem, err := client.ContainerInspect(ctx, req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := os.OpenFile(container.LogPath, os.O_RDWR|os.O_CREATE, 0666)
|
||||
if err := client.ContainerStop(ctx, containerItem.ID, container.StopOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := os.OpenFile(containerItem.LogPath, os.O_RDWR|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -545,10 +551,14 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
|
||||
}
|
||||
_, _ = file.Seek(0, 0)
|
||||
|
||||
files, _ := filepath.Glob(fmt.Sprintf("%s.*", container.LogPath))
|
||||
files, _ := filepath.Glob(fmt.Sprintf("%s.*", containerItem.LogPath))
|
||||
for _, file := range files {
|
||||
_ = os.Remove(file)
|
||||
}
|
||||
|
||||
if err := client.ContainerStart(ctx, containerItem.ID, types.ContainerStartOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -558,7 +568,7 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, container, sinc
|
||||
}
|
||||
command := fmt.Sprintf("docker logs %s", container)
|
||||
if tail != "0" {
|
||||
command += " -n " + tail
|
||||
command += " --tail " + tail
|
||||
}
|
||||
if since != "all" {
|
||||
command += " --since " + since
|
||||
@@ -631,9 +641,9 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
|
||||
func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) string {
|
||||
filePath := ""
|
||||
switch req.Type {
|
||||
case "image-pull", "image-push", "image-build":
|
||||
case "image-pull", "image-push", "image-build", "compose-create":
|
||||
filePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
|
||||
case "compose-detail", "compose-create":
|
||||
case "compose-detail":
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return ""
|
||||
@@ -833,6 +843,7 @@ 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
|
||||
@@ -921,3 +932,57 @@ 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
|
||||
}
|
||||
|
||||
@@ -159,8 +159,15 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
|
||||
if req.From == "path" {
|
||||
req.Name = path.Base(path.Dir(req.Path))
|
||||
}
|
||||
logName := path.Dir(req.Path) + "/compose.log"
|
||||
file, err := os.OpenFile(logName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
|
||||
dockerLogDir := path.Join(global.CONF.System.TmpDir, "docker_logs")
|
||||
if _, err := os.Stat(dockerLogDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dockerLogDir, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
logItem := fmt.Sprintf("%s/compose_create_%s_%s.log", dockerLogDir, req.Name, time.Now().Format("20060102150405"))
|
||||
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -181,7 +188,7 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
|
||||
_, _ = file.WriteString("docker-compose up successful!")
|
||||
}()
|
||||
|
||||
return req.Name, nil
|
||||
return path.Base(logItem), nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
|
||||
|
||||
@@ -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 == "website" || item.Type == "database" || item.Type == "directory" {
|
||||
if item.Type == "app" || item.Type == "website" || item.Type == "database" || item.Type == "directory" || item.Type == "snapshot" {
|
||||
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 == "database" || cronjob.Type == "website" || cronjob.Type == "directory") {
|
||||
if req.CleanData && (cronjob.Type == "app" || cronjob.Type == "database" || cronjob.Type == "website" || cronjob.Type == "directory" || cronjob.Type == "snapshot") {
|
||||
cronjob.RetainCopies = 0
|
||||
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||
if err != nil {
|
||||
@@ -261,6 +261,7 @@ 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
|
||||
|
||||
@@ -10,6 +10,7 @@ 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"
|
||||
@@ -38,6 +39,10 @@ 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
|
||||
@@ -47,9 +52,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
case "ntp":
|
||||
err = u.handleNtpSync()
|
||||
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
|
||||
case "website":
|
||||
record.File, err = u.handleBackup(cronjob, record.StartTime)
|
||||
case "database":
|
||||
case "website", "database", "app":
|
||||
record.File, err = u.handleBackup(cronjob, record.StartTime)
|
||||
case "directory":
|
||||
if len(cronjob.SourceDir) == 0 {
|
||||
@@ -62,6 +65,7 @@ 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
|
||||
@@ -85,7 +89,7 @@ func (u *CronjobService) handleShell(cronType, cornName, script string) ([]byte,
|
||||
}
|
||||
stdout, err := cmd.ExecCronjobWithTimeOut(script, handleDir, 24*time.Hour)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return []byte(stdout), err
|
||||
}
|
||||
return []byte(stdout), nil
|
||||
}
|
||||
@@ -120,6 +124,9 @@ 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
|
||||
@@ -186,6 +193,10 @@ 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)
|
||||
}
|
||||
}
|
||||
@@ -221,7 +232,7 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error {
|
||||
path = sourceDir
|
||||
}
|
||||
|
||||
commands := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s %s", targetDir+"/"+name, excludeRules, path)
|
||||
commands := fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s", targetDir+"/"+name, excludeRules, path)
|
||||
global.LOG.Debug(commands)
|
||||
stdout, err := cmd.ExecWithTimeOut(commands, 24*time.Hour)
|
||||
if err != nil {
|
||||
@@ -282,12 +293,13 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, backup model.Back
|
||||
for _, dbInfo := range dbs {
|
||||
var record model.BackupRecord
|
||||
|
||||
record.Type = "mysql"
|
||||
database, _ := databaseRepo.Get(commonRepo.WithByName(dbInfo.MysqlName))
|
||||
record.Type = database.Type
|
||||
record.Source = "LOCAL"
|
||||
record.BackupType = backup.Type
|
||||
|
||||
record.Name = dbInfo.MysqlName
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("database/mysql/%s/%s", record.Name, dbInfo.Name))
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", database.Type, 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
|
||||
@@ -396,6 +408,83 @@ 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()
|
||||
@@ -471,3 +560,27 @@ 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
|
||||
}
|
||||
|
||||
@@ -2,40 +2,43 @@ 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 RemoteDBService struct{}
|
||||
type DatabaseService struct{}
|
||||
|
||||
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
|
||||
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
|
||||
Delete(id uint) error
|
||||
List(dbType string) ([]dto.RemoteDBOption, error)
|
||||
List(dbType string) ([]dto.DatabaseOption, error)
|
||||
}
|
||||
|
||||
func NewIRemoteDBService() IRemoteDBService {
|
||||
return &RemoteDBService{}
|
||||
func NewIDatabaseService() IDatabaseService {
|
||||
return &DatabaseService{}
|
||||
}
|
||||
|
||||
func (u *RemoteDBService) SearchWithPage(search dto.RemoteDBSearch) (int64, interface{}, error) {
|
||||
total, dbs, err := remoteDBRepo.Page(search.Page, search.PageSize,
|
||||
commonRepo.WithByType(search.Type),
|
||||
func (u *DatabaseService) SearchWithPage(search dto.DatabaseSearch) (int64, interface{}, error) {
|
||||
total, dbs, err := databaseRepo.Page(search.Page, search.PageSize,
|
||||
databaseRepo.WithTypeList(search.Type),
|
||||
commonRepo.WithLikeName(search.Info),
|
||||
remoteDBRepo.WithoutByFrom("local"),
|
||||
databaseRepo.WithoutByFrom("local"),
|
||||
)
|
||||
var datas []dto.RemoteDBInfo
|
||||
var datas []dto.DatabaseInfo
|
||||
for _, db := range dbs {
|
||||
var item dto.RemoteDBInfo
|
||||
var item dto.DatabaseInfo
|
||||
if err := copier.Copy(&item, &db); err != nil {
|
||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
@@ -44,9 +47,9 @@ func (u *RemoteDBService) SearchWithPage(search dto.RemoteDBSearch) (int64, inte
|
||||
return total, datas, err
|
||||
}
|
||||
|
||||
func (u *RemoteDBService) Get(name string) (dto.RemoteDBInfo, error) {
|
||||
var data dto.RemoteDBInfo
|
||||
remote, err := remoteDBRepo.Get(commonRepo.WithByName(name))
|
||||
func (u *DatabaseService) Get(name string) (dto.DatabaseInfo, error) {
|
||||
var data dto.DatabaseInfo
|
||||
remote, err := databaseRepo.Get(commonRepo.WithByName(name))
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
@@ -56,20 +59,21 @@ func (u *RemoteDBService) Get(name string) (dto.RemoteDBInfo, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (u *RemoteDBService) List(dbType string) ([]dto.RemoteDBOption, error) {
|
||||
dbs, err := remoteDBRepo.GetList(commonRepo.WithByType(dbType))
|
||||
var datas []dto.RemoteDBOption
|
||||
func (u *DatabaseService) List(dbType string) ([]dto.DatabaseOption, error) {
|
||||
dbs, err := databaseRepo.GetList(databaseRepo.WithTypeList(dbType))
|
||||
var datas []dto.DatabaseOption
|
||||
for _, db := range dbs {
|
||||
var item dto.RemoteDBOption
|
||||
var item dto.DatabaseOption
|
||||
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 *RemoteDBService) CheckeRemoteDB(req dto.RemoteDBCreate) bool {
|
||||
func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
||||
if _, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
@@ -83,9 +87,12 @@ func (u *RemoteDBService) CheckeRemoteDB(req dto.RemoteDBCreate) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (u *RemoteDBService) Create(req dto.RemoteDBCreate) error {
|
||||
db, _ := remoteDBRepo.Get(commonRepo.WithByName(req.Name))
|
||||
func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
||||
db, _ := databaseRepo.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{
|
||||
@@ -101,29 +108,29 @@ func (u *RemoteDBService) Create(req dto.RemoteDBCreate) error {
|
||||
if err := copier.Copy(&db, &req); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
if err := remoteDBRepo.Create(&db); err != nil {
|
||||
if err := databaseRepo.Create(context.Background(), &db); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *RemoteDBService) Delete(id uint) error {
|
||||
db, _ := remoteDBRepo.Get(commonRepo.WithByID(id))
|
||||
func (u *DatabaseService) Delete(id uint) error {
|
||||
db, _ := databaseRepo.Get(commonRepo.WithByID(id))
|
||||
if db.ID == 0 {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
if err := remoteDBRepo.Delete(commonRepo.WithByID(id)); err != nil {
|
||||
if err := databaseRepo.Delete(context.Background(), commonRepo.WithByID(id)); err != nil {
|
||||
return err
|
||||
}
|
||||
if db.From != "local" {
|
||||
if err := mysqlRepo.Delete(context.Background(), remoteDBRepo.WithByFrom(db.Name)); err != nil {
|
||||
if err := mysqlRepo.Delete(context.Background(), mysqlRepo.WithByMysqlName(db.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *RemoteDBService) Update(req dto.RemoteDBUpdate) error {
|
||||
func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
|
||||
if _, err := mysql.NewMysqlClient(client.DBInfo{
|
||||
From: "remote",
|
||||
Address: req.Address,
|
||||
@@ -135,12 +142,18 @@ func (u *RemoteDBService) Update(req dto.RemoteDBUpdate) 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"] = req.Password
|
||||
upMap["password"] = pass
|
||||
upMap["description"] = req.Description
|
||||
return remoteDBRepo.Update(req.ID, upMap)
|
||||
return databaseRepo.Update(req.ID, upMap)
|
||||
}
|
||||
@@ -21,6 +21,7 @@ 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"
|
||||
@@ -34,18 +35,19 @@ 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(from string) error
|
||||
LoadFromRemote(req dto.MysqlLoadDB) error
|
||||
ChangeAccess(info dto.ChangeDBInfo) error
|
||||
ChangePassword(info dto.ChangeDBInfo) error
|
||||
UpdateVariables(updates []dto.MysqlVariablesUpdate) error
|
||||
UpdateVariables(req dto.MysqlVariablesUpdate) error
|
||||
UpdateConfByFile(info dto.MysqlConfUpdateByFile) error
|
||||
UpdateDescription(req dto.UpdateDescription) error
|
||||
DeleteCheck(id uint) ([]string, error)
|
||||
DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error)
|
||||
Delete(ctx context.Context, req dto.MysqlDBDelete) error
|
||||
LoadStatus() (*dto.MysqlStatus, error)
|
||||
LoadVariables() (*dto.MysqlVariables, error)
|
||||
LoadBaseInfo() (*dto.DBBaseInfo, error)
|
||||
LoadRemoteAccess() (bool, 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)
|
||||
|
||||
LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error)
|
||||
}
|
||||
@@ -56,7 +58,7 @@ func NewIMysqlService() IMysqlService {
|
||||
|
||||
func (u *MysqlService) SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error) {
|
||||
total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize,
|
||||
mysqlRepo.WithByFrom(search.From),
|
||||
mysqlRepo.WithByMysqlName(search.Database),
|
||||
commonRepo.WithLikeName(search.Info),
|
||||
commonRepo.WithOrderRuleBy(search.OrderBy, search.Order),
|
||||
)
|
||||
@@ -73,12 +75,26 @@ 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
|
||||
@@ -89,7 +105,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), remoteDBRepo.WithByFrom(req.From))
|
||||
mysql, _ := mysqlRepo.Get(commonRepo.WithByName(req.Name), mysqlRepo.WithByMysqlName(req.Database), databaseRepo.WithByFrom(req.From))
|
||||
if mysql.ID != 0 {
|
||||
return nil, constant.ErrRecordExist
|
||||
}
|
||||
@@ -103,20 +119,11 @@ 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.From)
|
||||
cli, version, err := LoadMysqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.From == "local" {
|
||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createItem.MysqlName = app.Name
|
||||
} else {
|
||||
createItem.MysqlName = req.From
|
||||
}
|
||||
createItem.MysqlName = req.Database
|
||||
defer cli.Close()
|
||||
if err := cli.Create(client.CreateInfo{
|
||||
Name: req.Name,
|
||||
@@ -137,22 +144,13 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
|
||||
return &createItem, nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) LoadFromRemote(from string) error {
|
||||
client, version, err := LoadMysqlClientByFrom(from)
|
||||
func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error {
|
||||
client, version, err := LoadMysqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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))
|
||||
databases, err := mysqlRepo.List(mysqlRepo.WithByMysqlName(req.Database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -163,7 +161,7 @@ func (u *MysqlService) LoadFromRemote(from string) error {
|
||||
for _, data := range datas {
|
||||
hasOld := false
|
||||
for _, oldData := range databases {
|
||||
if strings.EqualFold(oldData.Name, data.Name) {
|
||||
if strings.EqualFold(oldData.Name, data.Name) && strings.EqualFold(oldData.MysqlName, data.MysqlName) {
|
||||
hasOld = true
|
||||
break
|
||||
}
|
||||
@@ -173,7 +171,6 @@ func (u *MysqlService) LoadFromRemote(from string) 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
|
||||
}
|
||||
@@ -186,15 +183,15 @@ func (u *MysqlService) UpdateDescription(req dto.UpdateDescription) error {
|
||||
return mysqlRepo.Update(req.ID, map[string]interface{}{"description": req.Description})
|
||||
}
|
||||
|
||||
func (u *MysqlService) DeleteCheck(id uint) ([]string, error) {
|
||||
func (u *MysqlService) DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error) {
|
||||
var appInUsed []string
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(id))
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return appInUsed, err
|
||||
}
|
||||
|
||||
if db.From == "local" {
|
||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
||||
if err != nil {
|
||||
return appInUsed, err
|
||||
}
|
||||
@@ -223,7 +220,7 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
|
||||
if err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
cli, version, err := LoadMysqlClientByFrom(db.From)
|
||||
cli, version, err := LoadMysqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -234,41 +231,36 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
|
||||
Username: db.Username,
|
||||
Permission: db.Permission,
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
}); err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
if req.DeleteBackup {
|
||||
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/database/%s/%s/%s", req.Type, req.Database, db.Name))
|
||||
if _, err := os.Stat(uploadDir); err == nil {
|
||||
_ = os.RemoveAll(uploadDir)
|
||||
}
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("database/mysql/%s/%s", db.MysqlName, db.Name))
|
||||
backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", req.Type, db.MysqlName, db.Name))
|
||||
if _, err := os.Stat(backupDir); err == nil {
|
||||
_ = os.RemoveAll(backupDir)
|
||||
}
|
||||
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))
|
||||
global.LOG.Infof("delete database %s-%s backups successful", req.Database, 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(info dto.ChangeDBInfo) error {
|
||||
if cmd.CheckIllegal(info.Value) {
|
||||
func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
||||
if cmd.CheckIllegal(req.Value) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
cli, version, err := LoadMysqlClientByFrom(info.From)
|
||||
cli, version, err := LoadMysqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -277,12 +269,12 @@ func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error {
|
||||
mysqlData model.DatabaseMysql
|
||||
passwordInfo client.PasswordChangeInfo
|
||||
)
|
||||
passwordInfo.Password = info.Value
|
||||
passwordInfo.Password = req.Value
|
||||
passwordInfo.Timeout = 300
|
||||
passwordInfo.Version = version
|
||||
|
||||
if info.ID != 0 {
|
||||
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(info.ID))
|
||||
if req.ID != 0 {
|
||||
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -296,10 +288,10 @@ func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if info.ID != 0 {
|
||||
if req.ID != 0 {
|
||||
var appRess []model.AppInstallResource
|
||||
if info.From == "local" {
|
||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
if req.From == "local" {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -318,29 +310,30 @@ func (u *MysqlService) ChangePassword(info 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, info.Value); err != nil {
|
||||
if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", true, req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
global.LOG.Info("excute password change sql successful")
|
||||
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"password": info.Value})
|
||||
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})
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := updateInstallInfoInDB("mysql", "", "password", false, info.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := updateInstallInfoInDB("phpmyadmin", "", "password", true, info.Value); err != nil {
|
||||
if err := updateInstallInfoInDB(req.Type, req.Database, "password", false, req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
|
||||
if cmd.CheckIllegal(info.Value) {
|
||||
func (u *MysqlService) ChangeAccess(req dto.ChangeDBInfo) error {
|
||||
if cmd.CheckIllegal(req.Value) {
|
||||
return buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
cli, version, err := LoadMysqlClientByFrom(info.From)
|
||||
cli, version, err := LoadMysqlClientByFrom(req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -349,12 +342,12 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
|
||||
mysqlData model.DatabaseMysql
|
||||
accessInfo client.AccessChangeInfo
|
||||
)
|
||||
accessInfo.Permission = info.Value
|
||||
accessInfo.Permission = req.Value
|
||||
accessInfo.Timeout = 300
|
||||
accessInfo.Version = version
|
||||
|
||||
if info.ID != 0 {
|
||||
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(info.ID))
|
||||
if req.ID != 0 {
|
||||
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -370,40 +363,40 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
|
||||
}
|
||||
|
||||
if mysqlData.ID != 0 {
|
||||
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"permission": info.Value})
|
||||
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"permission": req.Value})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) UpdateConfByFile(info dto.MysqlConfUpdateByFile) error {
|
||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
func (u *MysqlService) UpdateConfByFile(req dto.MysqlConfUpdateByFile) error {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := fmt.Sprintf("%s/mysql/%s/conf/my.cnf", constant.AppInstallDir, app.Name)
|
||||
path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, 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(info.File)
|
||||
_, _ = write.WriteString(req.File)
|
||||
write.Flush()
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/mysql/%s/docker-compose.yml", constant.AppInstallDir, app.Name)); err != nil {
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) UpdateVariables(updates []dto.MysqlVariablesUpdate) error {
|
||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var files []string
|
||||
|
||||
path := fmt.Sprintf("%s/mysql/%s/conf/my.cnf", constant.AppInstallDir, app.Name)
|
||||
path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, app.Name)
|
||||
lineBytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -411,7 +404,7 @@ func (u *MysqlService) UpdateVariables(updates []dto.MysqlVariablesUpdate) error
|
||||
files = strings.Split(string(lineBytes), "\n")
|
||||
|
||||
group := "[mysqld]"
|
||||
for _, info := range updates {
|
||||
for _, info := range req.Variables {
|
||||
if !strings.HasPrefix(app.Version, "5.7") && !strings.HasPrefix(app.Version, "5.6") {
|
||||
if info.Param == "query_cache_size" {
|
||||
continue
|
||||
@@ -434,16 +427,16 @@ func (u *MysqlService) UpdateVariables(updates []dto.MysqlVariablesUpdate) error
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/mysql/%s/docker-compose.yml", constant.AppInstallDir, app.Name)); err != nil {
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) LoadBaseInfo() (*dto.DBBaseInfo, error) {
|
||||
func (u *MysqlService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error) {
|
||||
var data dto.DBBaseInfo
|
||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -454,8 +447,8 @@ func (u *MysqlService) LoadBaseInfo() (*dto.DBBaseInfo, error) {
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) LoadRemoteAccess() (bool, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -472,8 +465,8 @@ func (u *MysqlService) LoadRemoteAccess() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) LoadVariables() (*dto.MysqlVariables, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
func (u *MysqlService) LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -490,8 +483,8 @@ func (u *MysqlService) LoadVariables() (*dto.MysqlVariables, error) {
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error) {
|
||||
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -540,10 +533,14 @@ 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 "slow-logs":
|
||||
case "mysql-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")
|
||||
@@ -625,20 +622,21 @@ func updateMyCnf(oldFiles []string, group string, param string, value interface{
|
||||
return newFiles
|
||||
}
|
||||
|
||||
func LoadMysqlClientByFrom(from string) (mysql.MysqlClient, string, error) {
|
||||
func LoadMysqlClientByFrom(database string) (mysql.MysqlClient, string, error) {
|
||||
var (
|
||||
dbInfo client.DBInfo
|
||||
version string
|
||||
err error
|
||||
)
|
||||
|
||||
dbInfo.From = from
|
||||
dbInfo.Timeout = 300
|
||||
if from != "local" {
|
||||
databaseItem, err := remoteDBRepo.Get(commonRepo.WithByName(from))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
databaseItem, err := databaseRepo.Get(commonRepo.WithByName(database))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
dbInfo.From = databaseItem.From
|
||||
dbInfo.Database = database
|
||||
if dbInfo.From != "local" {
|
||||
dbInfo.Address = databaseItem.Address
|
||||
dbInfo.Port = databaseItem.Port
|
||||
dbInfo.Username = databaseItem.Username
|
||||
@@ -646,7 +644,7 @@ func LoadMysqlClientByFrom(from string) (mysql.MysqlClient, string, error) {
|
||||
version = databaseItem.Version
|
||||
|
||||
} else {
|
||||
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
app, err := appInstallRepo.LoadBaseInfo(databaseItem.Type, database)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ type RedisService struct{}
|
||||
type IRedisService interface {
|
||||
UpdateConf(req dto.RedisConfUpdate) error
|
||||
UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error
|
||||
ChangePassword(info dto.ChangeDBInfo) error
|
||||
ChangePassword(info dto.ChangeRedisPass) 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.ChangeDBInfo) error {
|
||||
func (u *RedisService) ChangePassword(req dto.ChangeRedisPass) error {
|
||||
if err := updateInstallInfoInDB("redis", "", "password", true, req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ var (
|
||||
appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
|
||||
|
||||
mysqlRepo = repo.NewIMysqlRepo()
|
||||
remoteDBRepo = repo.NewIRemoteDBRepo()
|
||||
databaseRepo = repo.NewIDatabaseRepo()
|
||||
|
||||
imageRepoRepo = repo.NewIImageRepoRepo()
|
||||
composeRepo = repo.NewIComposeTemplateRepo()
|
||||
|
||||
+229
-62
@@ -5,14 +5,18 @@ 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"
|
||||
@@ -27,6 +31,7 @@ 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
|
||||
}
|
||||
|
||||
@@ -36,7 +41,6 @@ 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 = "-"
|
||||
@@ -48,17 +52,22 @@ func (u *FirewallService) LoadBaseInfo() (dto.FirewallBaseInfo, error) {
|
||||
return baseInfo, err
|
||||
}
|
||||
baseInfo.Name = client.Name()
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
return baseInfo, nil
|
||||
}
|
||||
|
||||
@@ -67,6 +76,7 @@ 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
|
||||
@@ -100,14 +110,61 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
|
||||
datas = addrs
|
||||
}
|
||||
}
|
||||
total, start, end := len(datas), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||
|
||||
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
|
||||
if start > total {
|
||||
backDatas = make([]fireClient.FireInfo, 0)
|
||||
} else {
|
||||
if end >= total {
|
||||
end = total
|
||||
}
|
||||
backDatas = datas[start:end]
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if req.Type == "port" {
|
||||
@@ -127,6 +184,7 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
|
||||
}
|
||||
}
|
||||
}
|
||||
go u.cleanUnUsedData(client)
|
||||
|
||||
return int64(total), backDatas, nil
|
||||
}
|
||||
@@ -166,55 +224,92 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
protos := strings.Split(req.Protocol, "/")
|
||||
itemAddress := strings.Split(strings.TrimSuffix(req.Address, ","), ",")
|
||||
|
||||
var wg sync.WaitGroup
|
||||
if client.Name() == "ufw" {
|
||||
req.Port = strings.ReplaceAll(req.Port, "-", ":")
|
||||
if req.Operation == "remove" && req.Protocol == "tcp/udp" {
|
||||
req.Protocol = ""
|
||||
return u.operatePort(client, req)
|
||||
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)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
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)
|
||||
}
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
if req.Protocol == "tcp/udp" {
|
||||
if client.Name() == "firewalld" && strings.Contains(req.Port, ",") {
|
||||
ports := strings.Split(req.Port, ",")
|
||||
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
ports := strings.Split(itemPorts, ",")
|
||||
for _, port := range ports {
|
||||
if len(port) == 0 {
|
||||
continue
|
||||
}
|
||||
req.Port = port
|
||||
req.Protocol = "tcp"
|
||||
if err := u.operatePort(client, req); err != nil {
|
||||
return err
|
||||
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.Protocol = "udp"
|
||||
if err := u.operatePort(client, req); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
req.Protocol = "tcp"
|
||||
if err := u.operatePort(client, req); err != nil {
|
||||
return err
|
||||
}
|
||||
req.Protocol = "udp"
|
||||
if err := u.operatePort(client, req); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if strings.Contains(req.Port, ",") {
|
||||
ports := strings.Split(req.Port, ",")
|
||||
for _, port := range ports {
|
||||
req.Port = port
|
||||
if err := u.operatePort(client, req); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := u.operatePort(client, req); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
if reload {
|
||||
return client.Reload()
|
||||
}
|
||||
@@ -232,16 +327,24 @@ 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
|
||||
if err := client.RichRules(fireInfo, req.Operation); err != nil {
|
||||
return err
|
||||
}
|
||||
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)
|
||||
}
|
||||
wg.Wait()
|
||||
if reload {
|
||||
return client.Reload()
|
||||
}
|
||||
@@ -276,24 +379,38 @@ 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 {
|
||||
if err := u.OperatePortRule(rule, false); err != nil {
|
||||
return err
|
||||
}
|
||||
wgBatch.Add(1)
|
||||
go func(item dto.PortRuleOperate) {
|
||||
defer wgBatch.Done()
|
||||
_ = u.OperatePortRule(item, false)
|
||||
}(rule)
|
||||
}
|
||||
wgBatch.Wait()
|
||||
return client.Reload()
|
||||
}
|
||||
for _, rule := range req.Rules {
|
||||
itemRule := dto.AddrRuleOperate{Operation: rule.Operation, Address: rule.Address, Strategy: rule.Strategy}
|
||||
if err := u.OperateAddressRule(itemRule, false); err != nil {
|
||||
return err
|
||||
}
|
||||
wgBatch.Add(1)
|
||||
go func(item dto.AddrRuleOperate) {
|
||||
defer wgBatch.Done()
|
||||
_ = u.OperateAddressRule(item, false)
|
||||
}(itemRule)
|
||||
}
|
||||
return client.Reload()
|
||||
}
|
||||
@@ -323,7 +440,7 @@ func (u *FirewallService) operatePort(client firewall.FirewallClient, req dto.Po
|
||||
}
|
||||
|
||||
if client.Name() == "ufw" {
|
||||
if len(fireInfo.Address) != 0 && fireInfo.Address != "Anywhere" {
|
||||
if len(fireInfo.Address) != 0 && !strings.EqualFold(fireInfo.Address, "Anywhere") {
|
||||
return client.RichRules(fireInfo, req.Operation)
|
||||
}
|
||||
return client.Port(fireInfo, req.Operation)
|
||||
@@ -363,6 +480,29 @@ 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
|
||||
@@ -441,3 +581,30 @@ 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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,14 +3,6 @@ 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"
|
||||
@@ -22,6 +14,11 @@ 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{}
|
||||
@@ -34,7 +31,6 @@ type IHostToolService interface {
|
||||
GetToolLog(req request.HostToolLogReq) (string, error)
|
||||
OperateSupervisorProcess(req request.SupervisorProcessConfig) error
|
||||
GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error)
|
||||
LoadProcessStatus() []response.ProcessStatus
|
||||
OperateSupervisorProcessFile(req request.SupervisorProcessFileReq) (string, error)
|
||||
}
|
||||
|
||||
@@ -327,7 +323,10 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
||||
if err = configFile.SaveTo(iniPath); err != nil {
|
||||
return err
|
||||
}
|
||||
return operateSupervisorCtl("reload", "", "")
|
||||
if err := operateSupervisorCtl("reread", "", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
return operateSupervisorCtl("update", "", "")
|
||||
case "update":
|
||||
configFile, err := ini.Load(iniPath)
|
||||
if err != nil {
|
||||
@@ -350,7 +349,10 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
||||
if err = configFile.SaveTo(iniPath); err != nil {
|
||||
return err
|
||||
}
|
||||
return operateSupervisorCtl("reload", "", "")
|
||||
if err := operateSupervisorCtl("reread", "", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
return operateSupervisorCtl("update", "", "")
|
||||
case "restart":
|
||||
return operateSupervisorCtl("restart", req.Name, "")
|
||||
case "start":
|
||||
@@ -362,63 +364,15 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
||||
_ = files.NewFileOp().DeleteFile(iniPath)
|
||||
_ = files.NewFileOp().DeleteFile(outLog)
|
||||
_ = files.NewFileOp().DeleteFile(errLog)
|
||||
_ = operateSupervisorCtl("reload", "", "")
|
||||
if err := operateSupervisorCtl("reread", "", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
return operateSupervisorCtl("update", "", "")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HostToolService) LoadProcessStatus() []response.ProcessStatus {
|
||||
var datas []response.ProcessStatus
|
||||
statuLines, err := cmd.Exec("supervisorctl status")
|
||||
if err != nil {
|
||||
return datas
|
||||
}
|
||||
lines := strings.Split(string(statuLines), "\n")
|
||||
for _, line := range lines {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) > 1 {
|
||||
datas = append(datas, response.ProcessStatus{Name: fields[0]})
|
||||
}
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(datas))
|
||||
for i := 0; i < len(datas); i++ {
|
||||
go func(index int) {
|
||||
for t := 0; t < 3; t++ {
|
||||
status, err := cmd.ExecWithTimeOut(fmt.Sprintf("supervisorctl status %s", datas[index].Name), 3*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
|
||||
}
|
||||
datas[index].Name = fields[0]
|
||||
datas[index].Status = fields[1]
|
||||
if fields[1] != "RUNNING" {
|
||||
datas[index].Msg = strings.Join(fields[2:], " ")
|
||||
time.Sleep(1 * time.Second)
|
||||
continue
|
||||
}
|
||||
datas[index].PID = strings.TrimSuffix(fields[3], ",")
|
||||
datas[index].Uptime = fields[5]
|
||||
break
|
||||
}
|
||||
if len(datas[index].Status) == 0 {
|
||||
datas[index].Status = "FATAL"
|
||||
datas[index].Msg = "Timeout for getting process status"
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
return datas
|
||||
}
|
||||
|
||||
func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error) {
|
||||
var (
|
||||
result []response.SupervisorProcessConfig
|
||||
@@ -455,6 +409,7 @@ func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorPro
|
||||
if numprocs, _ := section.GetKey("numprocs"); numprocs != nil {
|
||||
config.Numprocs = numprocs.Value()
|
||||
}
|
||||
_ = getProcessStatus(&config)
|
||||
result = append(result, config)
|
||||
}
|
||||
}
|
||||
@@ -582,3 +537,29 @@ 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
|
||||
}
|
||||
|
||||
@@ -123,7 +123,6 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
fileName := "Dockerfile"
|
||||
dockerLogDir := path.Join(global.CONF.System.TmpDir, "docker_logs")
|
||||
if req.From == "edit" {
|
||||
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
@@ -158,6 +157,12 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
Labels: stringsToMap(req.Tags),
|
||||
}
|
||||
|
||||
dockerLogDir := path.Join(global.CONF.System.TmpDir, "docker_logs")
|
||||
if _, err := os.Stat(dockerLogDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dockerLogDir, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
logItem := fmt.Sprintf("%s/image_build_%s_%s.log", dockerLogDir, strings.ReplaceAll(req.Name, ":", "_"), time.Now().Format("20060102150405"))
|
||||
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -61,7 +62,15 @@ func (n NginxService) UpdateConfigByScope(req request.NginxConfigUpdate) error {
|
||||
}
|
||||
|
||||
func (n NginxService) GetStatus() (response.NginxStatus, error) {
|
||||
res, err := http.Get("http://127.0.0.1/nginx_status")
|
||||
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)
|
||||
if err != nil {
|
||||
return response.NginxStatus{}, err
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (err error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
composeContent, envContent, forms, err := handleParams(create.Image, create.Type, newNameDir, create.Params)
|
||||
composeContent, envContent, forms, err := handleParams(create.Image, create.Type, newNameDir, create.Source, create.Params)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -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, "")
|
||||
go buildRuntime(runtime, "", false)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -197,6 +197,9 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeRes, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := envs["CONTAINER_PACKAGE_URL"]; ok {
|
||||
res.Source = v
|
||||
}
|
||||
for _, form := range appForm.FormFields {
|
||||
if v, ok := envs[form.EnvKey]; ok {
|
||||
appParam := response.AppParam{
|
||||
@@ -252,7 +255,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
return buserr.New(constant.ErrImageExist)
|
||||
}
|
||||
runtimeDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
|
||||
composeContent, envContent, _, err := handleParams(req.Image, runtime.Type, runtimeDir, req.Params)
|
||||
composeContent, envContent, _, err := handleParams(req.Image, runtime.Type, runtimeDir, req.Source, req.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -272,6 +275,6 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go buildRuntime(runtime, imageID)
|
||||
go buildRuntime(runtime, imageID, req.Rebuild)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ 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"
|
||||
@@ -17,7 +18,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func buildRuntime(runtime *model.Runtime, oldImageID string) {
|
||||
func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
|
||||
runtimePath := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
|
||||
composePath := path.Join(runtimePath, "docker-compose.yml")
|
||||
logPath := path.Join(runtimePath, "build.log")
|
||||
@@ -61,11 +62,34 @@ func buildRuntime(runtime *model.Runtime, oldImageID string) {
|
||||
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)
|
||||
}
|
||||
|
||||
func handleParams(image, runtimeType, runtimeDir string, params map[string]interface{}) (composeContent []byte, envContent []byte, forms []byte, err error) {
|
||||
func handleParams(image, runtimeType, runtimeDir, source string, params map[string]interface{}) (composeContent []byte, envContent []byte, forms []byte, err error) {
|
||||
fileOp := files.NewFileOp()
|
||||
composeContent, err = fileOp.GetContent(path.Join(runtimeDir, "docker-compose.yml"))
|
||||
if err != nil {
|
||||
@@ -90,6 +114,7 @@ func handleParams(image, runtimeType, runtimeDir string, params map[string]inter
|
||||
params["PHP_EXTENSIONS"] = strings.Join(strArray, ",")
|
||||
}
|
||||
}
|
||||
params["CONTAINER_PACKAGE_URL"] = source
|
||||
}
|
||||
newMap := make(map[string]string)
|
||||
handleMap(params, newMap)
|
||||
|
||||
@@ -103,6 +103,12 @@ 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 {
|
||||
@@ -128,6 +134,7 @@ func (u *SettingService) Update(key, value string) error {
|
||||
}
|
||||
case "UserName", "Password":
|
||||
_ = global.SESSION.Clean()
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
+233
-200
@@ -9,6 +9,7 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@@ -16,6 +17,7 @@ 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"
|
||||
@@ -34,8 +36,12 @@ 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 {
|
||||
@@ -66,13 +72,14 @@ func (u *SnapshotService) SnapshotImport(req dto.SnapshotImport) error {
|
||||
}
|
||||
}
|
||||
for _, snap := range req.Names {
|
||||
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)
|
||||
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)
|
||||
}
|
||||
formatTime, err := time.Parse("20060102150405", strings.ReplaceAll(nameItems[2], ".tar.gz", ""))
|
||||
if err != nil {
|
||||
return fmt.Errorf("incorrect snapshot name format of %s", snap)
|
||||
return fmt.Errorf("incorrect snapshot name format of %s", shortName)
|
||||
}
|
||||
if strings.HasSuffix(snap, ".tar.gz") {
|
||||
snap = strings.ReplaceAll(snap, ".tar.gz", "")
|
||||
@@ -99,6 +106,18 @@ 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"`
|
||||
@@ -113,112 +132,9 @@ type SnapshotJson struct {
|
||||
}
|
||||
|
||||
func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
||||
global.LOG.Info("start to create snapshot now")
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
if _, _, err := u.HandleSnapshot(false, req, time.Now().Format("20060102150405")); 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
|
||||
}
|
||||
|
||||
@@ -553,14 +469,135 @@ 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 := u.handleTar(source, target, "docker_data.tar.gz", ""); err != nil {
|
||||
if err := handleSnapTar(source, target, "docker_data.tar.gz", ""); err != nil {
|
||||
return fmt.Errorf("backup docker data failed, err: %v", err)
|
||||
}
|
||||
case "recover":
|
||||
if err := u.handleTar(target, u.OriginalPath, "docker_data.tar.gz", ""); err != nil {
|
||||
if err := handleSnapTar(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 {
|
||||
@@ -581,31 +618,6 @@ 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)
|
||||
@@ -663,7 +675,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(panelPath, target); err != nil {
|
||||
if err := cpBinary([]string{panelPath}, target); err != nil {
|
||||
return fmt.Errorf("backup 1panel binary failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -672,7 +684,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(source, "/usr/local/bin/1panel"); err != nil {
|
||||
if err := cpBinary([]string{source}, "/usr/local/bin/1panel"); err != nil {
|
||||
return fmt.Errorf("recover 1panel binary failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -687,7 +699,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(panelctlPath, target); err != nil {
|
||||
if err := cpBinary([]string{panelctlPath}, target); err != nil {
|
||||
return fmt.Errorf("backup 1pctl binary failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -696,7 +708,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(source, "/usr/local/bin/1pctl"); err != nil {
|
||||
if err := cpBinary([]string{source}, "/usr/local/bin/1pctl"); err != nil {
|
||||
return fmt.Errorf("recover 1pctl binary failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -711,7 +723,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(panelServicePath, target); err != nil {
|
||||
if err := cpBinary([]string{panelServicePath}, target); err != nil {
|
||||
return fmt.Errorf("backup 1panel service failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -720,7 +732,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(source, "/etc/systemd/system/1panel.service"); err != nil {
|
||||
if err := cpBinary([]string{source}, "/etc/systemd/system/1panel.service"); err != nil {
|
||||
return fmt.Errorf("recover 1panel service failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -731,12 +743,8 @@ 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 := u.handleTar(target, u.OriginalPath, "1panel_backup.tar.gz", "./system;"); err != nil {
|
||||
if err := handleSnapTar(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 {
|
||||
@@ -758,7 +766,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;./db/1Panel.db-*;"
|
||||
exclusionRules := "./tmp;./log;./cache;"
|
||||
if strings.Contains(backupDir, source) {
|
||||
exclusionRules += ("." + strings.ReplaceAll(backupDir, source, "") + ";")
|
||||
}
|
||||
@@ -766,11 +774,11 @@ func (u *SnapshotService) handlePanelDatas(snapID uint, fileOp files.FileOp, ope
|
||||
exclusionRules += ("." + strings.ReplaceAll(dockerDir, source, "") + ";")
|
||||
}
|
||||
|
||||
if err := u.handleTar(source, target, "1panel_data.tar.gz", exclusionRules); err != nil {
|
||||
if err := handleSnapTar(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;./db/1Panel.db-*;"
|
||||
exclusionRules := "./tmp;./log;./cache;"
|
||||
if strings.Contains(backupDir, target) {
|
||||
exclusionRules += ("." + strings.ReplaceAll(backupDir, target, "") + ";")
|
||||
}
|
||||
@@ -779,7 +787,7 @@ func (u *SnapshotService) handlePanelDatas(snapID uint, fileOp files.FileOp, ope
|
||||
}
|
||||
|
||||
_ = snapshotRepo.Update(snapID, map[string]interface{}{"recover_status": ""})
|
||||
if err := u.handleTar(target, u.OriginalPath, "1panel_data.tar.gz", exclusionRules); err != nil {
|
||||
if err := handleSnapTar(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})
|
||||
@@ -821,10 +829,13 @@ func (u *SnapshotService) Delete(req dto.BatchDeleteReq) error {
|
||||
return err
|
||||
}
|
||||
for _, snap := range backups {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
if err := snapshotRepo.Delete(commonRepo.WithIdsIn(req.Ids)); err != nil {
|
||||
return err
|
||||
@@ -833,18 +844,6 @@ 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)
|
||||
@@ -884,10 +883,11 @@ func updateRollbackStatus(id uint, status string, message string) {
|
||||
}
|
||||
}
|
||||
|
||||
func cpBinary(src, dst string) error {
|
||||
stderr, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", src, dst))
|
||||
func cpBinary(src []string, dst string) error {
|
||||
global.LOG.Debugf(fmt.Sprintf("\\cp -f %s %s", strings.Join(src, " "), dst))
|
||||
stdout, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", strings.Join(src, " "), dst))
|
||||
if err != nil {
|
||||
return errors.New(stderr)
|
||||
return fmt.Errorf("cp file failed, stdout: %v, err: %v", stdout, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -939,35 +939,6 @@ 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 {
|
||||
@@ -988,14 +959,35 @@ 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
|
||||
}
|
||||
for _, install := range appInstalls {
|
||||
_ = rebuildApp(install)
|
||||
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])
|
||||
}
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1035,3 +1027,44 @@ 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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
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.LoadSizeUnit2F(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
|
||||
}
|
||||
+40
-13
@@ -18,6 +18,8 @@ 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"
|
||||
@@ -51,19 +53,20 @@ func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
|
||||
PermitRootLogin: "yes",
|
||||
UseDNS: "yes",
|
||||
}
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
stdout, err := cmd.Execf("%s systemctl status sshd", sudo)
|
||||
serviceName, err := loadServiceName()
|
||||
if err != nil {
|
||||
data.Message = stdout
|
||||
data.Status = constant.StatusDisable
|
||||
}
|
||||
stdLines := strings.Split(stdout, "\n")
|
||||
for _, stdline := range stdLines {
|
||||
if strings.Contains(stdline, "active (running)") {
|
||||
data.Message = err.Error()
|
||||
} else {
|
||||
active, err := systemctl.IsActive(serviceName)
|
||||
if !active {
|
||||
data.Status = constant.StatusDisable
|
||||
data.Message = err.Error()
|
||||
} else {
|
||||
data.Status = constant.StatusEnable
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
sshConf, err := os.ReadFile(sshPath)
|
||||
if err != nil {
|
||||
data.Message = err.Error()
|
||||
@@ -95,10 +98,14 @@ func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
|
||||
|
||||
func (u *SSHService) OperateSSH(operation string) error {
|
||||
if operation == "start" || operation == "stop" || operation == "restart" {
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
stdout, err := cmd.Execf("%s systemctl %s sshd", sudo, operation)
|
||||
serviceName, err := loadServiceName()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s sshd failed, stdout: %s, err: %v", operation, stdout, err)
|
||||
return err
|
||||
}
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
stdout, err := cmd.Execf("%s systemctl %s %s", sudo, operation, serviceName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s %s failed, stdout: %s, err: %v", operation, serviceName, stdout, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -106,6 +113,11 @@ 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
|
||||
@@ -130,11 +142,17 @@ 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 sshd", sudo)
|
||||
|
||||
_, _ = cmd.Execf("%s systemctl restart %s", sudo, serviceName)
|
||||
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
|
||||
@@ -144,7 +162,7 @@ func (u *SSHService) UpdateByFile(value string) error {
|
||||
return err
|
||||
}
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
_, _ = cmd.Execf("%s systemctl restart sshd", sudo)
|
||||
_, _ = cmd.Execf("%s systemctl restart %s", sudo, serviceName)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -458,3 +476,12 @@ 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")
|
||||
}
|
||||
|
||||
@@ -104,6 +104,10 @@ 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")
|
||||
@@ -127,26 +131,26 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
}
|
||||
global.LOG.Info("backup original data successful, now start to upgrade!")
|
||||
|
||||
if err := cpBinary(tmpDir+"/1panel", "/usr/local/bin/1panel"); err != nil {
|
||||
u.handleRollback(fileOp, originalDir, 1)
|
||||
if err := cpBinary([]string{tmpDir + "/1panel"}, "/usr/local/bin/1panel"); err != nil {
|
||||
global.LOG.Errorf("upgrade 1panel failed, err: %v", err)
|
||||
u.handleRollback(fileOp, originalDir, 1)
|
||||
return
|
||||
}
|
||||
|
||||
if err := cpBinary(tmpDir+"/1pctl", "/usr/local/bin/1pctl"); err != nil {
|
||||
u.handleRollback(fileOp, originalDir, 2)
|
||||
if err := cpBinary([]string{tmpDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
|
||||
global.LOG.Errorf("upgrade 1pctl failed, err: %v", err)
|
||||
u.handleRollback(fileOp, originalDir, 2)
|
||||
return
|
||||
}
|
||||
if _, err := cmd.Execf("sed -i -e 's#BASE_DIR=.*#BASE_DIR=%s#g' /usr/local/bin/1pctl", global.CONF.System.BaseDir); err != nil {
|
||||
u.handleRollback(fileOp, originalDir, 2)
|
||||
global.LOG.Errorf("upgrade basedir in 1pctl failed, err: %v", err)
|
||||
u.handleRollback(fileOp, originalDir, 2)
|
||||
return
|
||||
}
|
||||
|
||||
if err := cpBinary(tmpDir+"/1panel.service", "/etc/systemd/system/1panel.service"); err != nil {
|
||||
u.handleRollback(fileOp, originalDir, 3)
|
||||
if err := cpBinary([]string{tmpDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
|
||||
global.LOG.Errorf("upgrade 1panel.service failed, err: %v", err)
|
||||
u.handleRollback(fileOp, originalDir, 3)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -179,22 +183,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(originalDir+"/1Panel.db", dbPath); err != nil {
|
||||
if err := cpBinary([]string{originalDir + "/1Panel.db"}, dbPath); err != nil {
|
||||
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
||||
}
|
||||
if err := cpBinary(originalDir+"/1panel", "/usr/local/bin/1panel"); err != nil {
|
||||
if err := cpBinary([]string{originalDir + "/1panel"}, "/usr/local/bin/1panel"); err != nil {
|
||||
global.LOG.Errorf("rollback 1pctl failed, err: %v", err)
|
||||
}
|
||||
if errStep == 1 {
|
||||
return
|
||||
}
|
||||
if err := cpBinary(originalDir+"/1pctl", "/usr/local/bin/1pctl"); err != nil {
|
||||
if err := cpBinary([]string{originalDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
|
||||
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
||||
}
|
||||
if errStep == 2 {
|
||||
return
|
||||
}
|
||||
if err := cpBinary(originalDir+"/1panel.service", "/etc/systemd/system/1panel.service"); err != nil {
|
||||
if err := cpBinary([]string{originalDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
|
||||
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,18 @@ 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"
|
||||
@@ -80,6 +84,7 @@ 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)
|
||||
@@ -175,6 +180,11 @@ 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{
|
||||
@@ -291,13 +301,13 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
}
|
||||
|
||||
var domains []model.WebsiteDomain
|
||||
domains = append(domains, model.WebsiteDomain{Domain: website.PrimaryDomain, Port: 80})
|
||||
domains = append(domains, model.WebsiteDomain{Domain: website.PrimaryDomain, Port: defaultHttpPort})
|
||||
otherDomainArray := strings.Split(create.OtherDomains, "\n")
|
||||
for _, domain := range otherDomainArray {
|
||||
if domain == "" {
|
||||
continue
|
||||
}
|
||||
domainModel, err := getDomain(domain)
|
||||
domainModel, err := getDomain(domain, defaultHttpPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -445,11 +455,20 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
ports []int
|
||||
domains []string
|
||||
)
|
||||
if create.Port != 80 {
|
||||
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 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
|
||||
@@ -466,7 +485,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
Port: create.Port,
|
||||
WebsiteID: create.WebsiteID,
|
||||
}
|
||||
if create.Port != 80 {
|
||||
if create.Port != httpPort {
|
||||
go func() {
|
||||
_ = OperateFirewallPort(nil, []int{create.Port})
|
||||
}()
|
||||
@@ -652,7 +671,12 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
|
||||
if !req.Enable {
|
||||
website.Protocol = constant.ProtocolHTTP
|
||||
website.WebsiteSSLID = 0
|
||||
if err := deleteListenAndServerName(website, []string{"443", "[::]:443"}, []string{}); err != nil {
|
||||
_, 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 {
|
||||
return nil, err
|
||||
}
|
||||
nginxParams := getNginxParamsFromStaticFile(dto.SSL, nil)
|
||||
@@ -793,7 +817,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
|
||||
}
|
||||
}
|
||||
@@ -912,19 +936,13 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi
|
||||
}
|
||||
}
|
||||
filePath := path.Join(sitePath, "log", req.LogType)
|
||||
fileInfo, err := os.Stat(filePath)
|
||||
lines, end, err := files.ReadFileByLine(filePath, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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)
|
||||
res.End = end
|
||||
res.Path = filePath
|
||||
res.Content = strings.Join(lines, "\n")
|
||||
return res, nil
|
||||
case constant.DisableLog:
|
||||
key := "access_log"
|
||||
@@ -1007,12 +1025,17 @@ 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 == "80" || bind == "443" || bind == "[::]:80" || bind == "[::]:443" {
|
||||
if bind == strconv.Itoa(httpPort) || bind == strconv.Itoa(httpsPort) || bind == "[::]:"+strconv.Itoa(httpPort) || bind == "[::]:"+strconv.Itoa(httpsPort) {
|
||||
if param.Params[paramLen-1] == components.DefaultServer {
|
||||
newParam = param.Params
|
||||
} else {
|
||||
@@ -1188,6 +1211,9 @@ func (w WebsiteService) UpdatePHPConfigFile(req request.WebsitePHPFileUpdate) er
|
||||
if err := files.NewFileOp().WriteFile(configPath, strings.NewReader(req.Content), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(runtimeInstall.GetComposePath()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1372,7 +1398,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
|
||||
@@ -1391,9 +1417,6 @@ 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)
|
||||
@@ -2301,3 +2324,52 @@ 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
|
||||
}
|
||||
|
||||
@@ -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(constant.AppInstallDir, constant.AppOpenresty, appInstall.Name, "root")); err != nil {
|
||||
if err := client.UseHTTP(path.Join(appInstall.GetPath(), "root")); err != nil {
|
||||
return res, err
|
||||
}
|
||||
websiteSSL.AutoRenew = create.AutoRenew
|
||||
|
||||
@@ -23,12 +23,12 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func getDomain(domainStr string) (model.WebsiteDomain, error) {
|
||||
func getDomain(domainStr string, defaultPort int) (model.WebsiteDomain, error) {
|
||||
domain := model.WebsiteDomain{}
|
||||
domainArray := strings.Split(domainStr, ":")
|
||||
if len(domainArray) == 1 {
|
||||
domain.Domain = domainArray[0]
|
||||
domain.Port = 80
|
||||
domain.Port = defaultPort
|
||||
return domain, nil
|
||||
}
|
||||
if len(domainArray) > 1 {
|
||||
@@ -186,6 +186,7 @@ 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)
|
||||
@@ -378,27 +379,33 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
|
||||
}
|
||||
config := nginxFull.SiteConfig.Config
|
||||
server := config.FindServers()[0]
|
||||
server.UpdateListen("443", website.DefaultServer, "ssl", "http2")
|
||||
|
||||
httpPort := strconv.Itoa(nginxFull.Install.HttpPort)
|
||||
httpsPort := strconv.Itoa(nginxFull.Install.HttpsPort)
|
||||
httpPortIPV6 := "[::]:" + httpPort
|
||||
httpsPortIPV6 := "[::]:" + httpsPort
|
||||
|
||||
server.UpdateListen(httpsPort, website.DefaultServer, "ssl", "http2")
|
||||
if website.IPV6 {
|
||||
server.UpdateListen("[::]:443", website.DefaultServer, "ssl", "http2")
|
||||
server.UpdateListen(httpsPortIPV6, website.DefaultServer, "ssl", "http2")
|
||||
}
|
||||
|
||||
switch req.HttpConfig {
|
||||
case constant.HTTPSOnly:
|
||||
server.RemoveListenByBind("80")
|
||||
server.RemoveListenByBind("[::]:80")
|
||||
server.RemoveListenByBind(httpPort)
|
||||
server.RemoveListenByBind(httpPortIPV6)
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
case constant.HTTPToHTTPS:
|
||||
server.UpdateListen("80", website.DefaultServer)
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
if website.IPV6 {
|
||||
server.UpdateListen("[::]:80", website.DefaultServer)
|
||||
server.UpdateListen(httpPortIPV6, website.DefaultServer)
|
||||
}
|
||||
server.AddHTTP2HTTPS()
|
||||
case constant.HTTPAlso:
|
||||
server.UpdateListen("80", website.DefaultServer)
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
if website.IPV6 {
|
||||
server.UpdateListen("[::]:80", website.DefaultServer)
|
||||
server.UpdateListen(httpPortIPV6, website.DefaultServer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,7 +633,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
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ const (
|
||||
Upgrading = "Upgrading"
|
||||
UpgradeErr = "UpgradeErr"
|
||||
PullErr = "PullErr"
|
||||
Rebuilding = "Rebuilding"
|
||||
|
||||
ContainerPrefix = "1Panel-"
|
||||
|
||||
@@ -20,6 +21,7 @@ const (
|
||||
|
||||
AppOpenresty = "openresty"
|
||||
AppMysql = "mysql"
|
||||
AppMariaDB = "mariadb"
|
||||
AppRedis = "redis"
|
||||
|
||||
AppResourceLocal = "local"
|
||||
|
||||
@@ -96,6 +96,8 @@ var (
|
||||
ErrUserIsExist = "ErrUserIsExist"
|
||||
ErrDatabaseIsExist = "ErrDatabaseIsExist"
|
||||
ErrExecTimeOut = "ErrExecTimeOut"
|
||||
ErrRemoteExist = "ErrRemoteExist"
|
||||
ErrLocalExist = "ErrLocalExist"
|
||||
)
|
||||
|
||||
// redis
|
||||
@@ -122,4 +124,5 @@ var (
|
||||
var (
|
||||
ErrBackupInUsed = "ErrBackupInUsed"
|
||||
ErrOSSConn = "ErrOSSConn"
|
||||
ErrEntrance = "ErrEntrance"
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ package constant
|
||||
|
||||
const (
|
||||
StatusRunning = "Running"
|
||||
StatusDone = "Done"
|
||||
StatusStoped = "Stoped"
|
||||
StatusWaiting = "Waiting"
|
||||
StatusSuccess = "Success"
|
||||
|
||||
@@ -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 {{ .apps }}"
|
||||
ErrPortInOtherApp: "{{ .port }} port already in use by app {{ .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!'
|
||||
@@ -46,6 +46,7 @@ ErrContainerNotFound: '{{ .name }} container does not exist'
|
||||
ErrContainerMsg: '{{ .name }} container is abnormal, please check the log on the container page for details'
|
||||
ErrAppBackup: '{{ .name }} application backup failed err {{.err}}'
|
||||
ErrImagePull: '{{ .name }} image pull failed err {{.err}}'
|
||||
ErrVersionTooLow: 'The current 1Panel version is too low to update the app store, please upgrade the version'
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "File can not read"
|
||||
@@ -65,6 +66,7 @@ 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"
|
||||
@@ -80,6 +82,8 @@ 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"
|
||||
@@ -99,6 +103,7 @@ 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"
|
||||
|
||||
@@ -20,7 +20,7 @@ ErrPortInUsed: "{{ .detail }} 端口已被佔用!"
|
||||
ErrAppLimit: "應用超出安裝數量限制"
|
||||
ErrAppRequired: "請先安裝 {{ .detail }} 應用"
|
||||
ErrNotInstall: "應用未安裝"
|
||||
ErrPortInOtherApp: "{{ .port }} 端口已被 {{ .apps }}佔用!"
|
||||
ErrPortInOtherApp: "{{ .port }} 端口已被應用 {{ .apps }} 佔用!"
|
||||
ErrDbUserNotValid: "儲存資料庫,用戶名密碼不匹配!"
|
||||
ErrDockerComposeNotValid: "docker-compose 文件格式錯誤"
|
||||
ErrUpdateBuWebsite: '應用更新成功,但是網站配置文件修改失敗,請檢查配置!'
|
||||
@@ -46,6 +46,7 @@ ErrContainerNotFound: '{{ .name }} 容器不存在'
|
||||
ErrContainerMsg: '{{ .name }} 容器異常,具體請在容器頁面查看日誌'
|
||||
ErrAppBackup: '{{ .name }} 應用備份失敗 err {{.err}}'
|
||||
ErrImagePull: '{{ .name }} 鏡像拉取失敗 err {{.err}}'
|
||||
ErrVersionTooLow: '當前 1Panel 版本過低,無法更新應用商店,請升級版本之後操作'
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "此文件不支持預覽"
|
||||
@@ -65,6 +66,7 @@ ErrGroupIsUsed: '分組正在使用中,無法刪除'
|
||||
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}"'
|
||||
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}"'
|
||||
ErrPHPResource: '本地運行環境不支持切換!'
|
||||
ErrPathPermission: 'index 目錄下檢測到非 1000:1000 權限文件夾,可能導致網站訪問 Access denied 錯誤'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "證書正在被網站使用,無法刪除"
|
||||
@@ -80,6 +82,8 @@ ErrSSLCertificateFormat: '證書文件格式錯誤,請使用 pem 格式'
|
||||
ErrUserIsExist: "當前用戶已存在,請重新輸入"
|
||||
ErrDatabaseIsExist: "當前資料庫已存在,請重新輸入"
|
||||
ErrExecTimeOut: "SQL 執行超時,請檢查數據庫"
|
||||
ErrRemoteExist: "遠程數據庫已存在該名稱,請修改後重試"
|
||||
ErrLocalExist: "本地數據庫已存在該名稱,請修改後重試"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: "恢復文件類型與當前持久化方式不符,請修改後重試"
|
||||
@@ -99,6 +103,7 @@ ErrDelWithWebsite: "運行環境已經關聯網站,無法刪除"
|
||||
#setting
|
||||
ErrBackupInUsed: "該備份帳號已在計劃任務中使用,無法刪除"
|
||||
ErrOSSConn: "無法成功請求最新版本,請檢查伺服器是否能夠連接到外部網絡環境。"
|
||||
ErrEntrance: "安全入口信息錯誤,請檢查後重試!"
|
||||
|
||||
#tool
|
||||
ErrConfigNotFound: "配置文件不存在"
|
||||
|
||||
@@ -20,7 +20,7 @@ ErrPortInUsed: "{{ .detail }} 端口已被占用!"
|
||||
ErrAppLimit: "应用超出安装数量限制"
|
||||
ErrAppRequired: "请先安装 {{ .detail }} 应用"
|
||||
ErrNotInstall: "应用未安装"
|
||||
ErrPortInOtherApp: "{{ .port }} 端口已被 {{ .apps }}占用!"
|
||||
ErrPortInOtherApp: "{{ .port }} 端口已被应用 {{ .apps }} 占用!"
|
||||
ErrDbUserNotValid: "存量数据库,用户名密码不匹配!"
|
||||
ErrDockerComposeNotValid: "docker-compose 文件格式错误"
|
||||
ErrUpdateBuWebsite: '应用更新成功,但是网站配置文件修改失败,请检查配置!'
|
||||
@@ -46,6 +46,7 @@ ErrContainerNotFound: '{{ .name }} 容器不存在'
|
||||
ErrContainerMsg: '{{ .name }} 容器异常,具体请在容器页面查看日志'
|
||||
ErrAppBackup: '{{ .name }} 应用备份失败 err {{.err}}'
|
||||
ErrImagePull: '镜像拉取失败 {{.err}}'
|
||||
ErrVersionTooLow: '当前 1Panel 版本过低,无法更新应用商店,请升级版本之后操作'
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "此文件不支持预览"
|
||||
@@ -65,6 +66,7 @@ ErrGroupIsUsed: '分组正在使用中,无法删除'
|
||||
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}"'
|
||||
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}"'
|
||||
ErrPHPResource: '本地运行环境不支持切换!'
|
||||
ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "证书正在被网站使用,无法删除"
|
||||
@@ -80,6 +82,8 @@ ErrSSLCertificateFormat: '证书文件格式错误,请使用 pem 格式'
|
||||
ErrUserIsExist: "当前用户已存在,请重新输入"
|
||||
ErrDatabaseIsExist: "当前数据库已存在,请重新输入"
|
||||
ErrExecTimeOut: "SQL 执行超时,请检查数据库"
|
||||
ErrRemoteExist: "远程数据库已存在该名称,请修改后重试"
|
||||
ErrLocalExist: "本地数据库已存在该名称,请修改后重试"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
|
||||
@@ -99,6 +103,7 @@ ErrDelWithWebsite: "运行环境已经关联网站,无法删除"
|
||||
#setting
|
||||
ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除"
|
||||
ErrOSSConn: "无法成功请求最新版本,请检查服务器是否能够连接到外部网络环境。"
|
||||
ErrEntrance: "安全入口信息错误,请检查后重试!"
|
||||
|
||||
#tool
|
||||
ErrConfigNotFound: "配置文件不存在"
|
||||
|
||||
@@ -4,6 +4,7 @@ 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"
|
||||
@@ -17,11 +18,6 @@ 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)
|
||||
@@ -63,4 +59,51 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,11 @@ func Init() {
|
||||
migrations.AddRemoteDB,
|
||||
migrations.UpdateRedisParam,
|
||||
migrations.UpdateCronjobWithDb,
|
||||
migrations.AddTableFirewall,
|
||||
migrations.AddDatabases,
|
||||
migrations.UpdateDatabase,
|
||||
migrations.UpdateAppInstallResource,
|
||||
migrations.DropDatabaseLocal,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
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"
|
||||
@@ -485,40 +486,23 @@ var EncryptHostPassword = &gormigrate.Migration{
|
||||
var AddRemoteDB = &gormigrate.Migration{
|
||||
ID: "20230724-add-remote-db",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.AutoMigrate(&model.RemoteDB{}, &model.DatabaseMysql{}); err != nil {
|
||||
if err := tx.AutoMigrate(&model.Database{}, &model.DatabaseMysql{}); 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
|
||||
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
|
||||
}
|
||||
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
|
||||
},
|
||||
@@ -531,10 +515,10 @@ var UpdateRedisParam = &gormigrate.Migration{
|
||||
app model.App
|
||||
appInstall model.AppInstall
|
||||
)
|
||||
if err := global.DB.Where("key = ?", "redis").First(&app).Error; err != nil {
|
||||
if err := tx.Where("key = ?", "redis").First(&app).Error; err != nil {
|
||||
return nil
|
||||
}
|
||||
if err := global.DB.Where("app_id = ?", app.ID).First(&appInstall).Error; err != nil {
|
||||
if err := tx.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")
|
||||
@@ -544,7 +528,6 @@ var UpdateRedisParam = &gormigrate.Migration{
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
@@ -552,13 +535,13 @@ var UpdateCronjobWithDb = &gormigrate.Migration{
|
||||
ID: "20230809-update-cronjob-with-db",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
var cronjobs []model.Cronjob
|
||||
if err := global.DB.Where("type = ? AND db_name != ?", "database", "all").Find(&cronjobs).Error; err != nil {
|
||||
if err := tx.Where("type = ? AND db_name != ?", "database", "all").Find(&cronjobs).Error; err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, job := range cronjobs {
|
||||
var db model.DatabaseMysql
|
||||
if err := global.DB.Where("name = ?", job.DBName).First(&db).Error; err != nil {
|
||||
if err := tx.Where("name = ?", job.DBName).First(&db).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
if err := tx.Model(&model.Cronjob{}).
|
||||
@@ -570,3 +553,191 @@ 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()
|
||||
_ = tx.Where("name = ? AND address = ?", "local", "127.0.0.1").Delete(&model.Database{}).Error
|
||||
mysql := addDatabaseData(tx, installRepo, "mysql")
|
||||
if mysql.AppInstallID != 0 {
|
||||
if err := tx.Create(mysql).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
mariadb := addDatabaseData(tx, installRepo, "mariadb")
|
||||
if mariadb.AppInstallID != 0 {
|
||||
if err := tx.Create(mariadb).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
redis := addDatabaseData(tx, installRepo, "redis")
|
||||
if redis.AppInstallID != 0 {
|
||||
if err := tx.Create(redis).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
postgresql := addDatabaseData(tx, installRepo, "postgresql")
|
||||
if postgresql.AppInstallID != 0 {
|
||||
if err := tx.Create(postgresql).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
mongodb := addDatabaseData(tx, installRepo, "mongodb")
|
||||
if mongodb.AppInstallID != 0 {
|
||||
if err := tx.Create(mongodb).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
memcached := addDatabaseData(tx, installRepo, "memcached")
|
||||
if memcached.AppInstallID != 0 {
|
||||
if err := tx.Create(memcached).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 {
|
||||
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
|
||||
},
|
||||
}
|
||||
|
||||
var DropDatabaseLocal = &gormigrate.Migration{
|
||||
ID: "20230914-drop-database-local",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
_ = tx.Where("name = ? AND address = ?", "local", "127.0.0.1").Delete(&model.Database{}).Error
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func addDatabaseData(tx *gorm.DB, installRepo repo.IAppInstallRepo, appType string) *model.Database {
|
||||
dbInfo, err := installRepo.LoadBaseInfo(appType, "")
|
||||
if err != nil {
|
||||
return &model.Database{}
|
||||
}
|
||||
|
||||
if appType == "mysql" || appType == "redis" || appType == "mariadb" || appType == "memcached" {
|
||||
dbInfo.UserName = "root"
|
||||
}
|
||||
database := &model.Database{
|
||||
AppInstallID: dbInfo.ID,
|
||||
Name: dbInfo.Name,
|
||||
Type: appType,
|
||||
Version: dbInfo.Version,
|
||||
From: "local",
|
||||
Address: dbInfo.ServiceName,
|
||||
Port: service.DatabaseKeys[appType],
|
||||
Username: dbInfo.UserName,
|
||||
Password: dbInfo.Password,
|
||||
}
|
||||
var dbItem model.Database
|
||||
_ = global.DB.Where("name = ?", dbInfo.Name).First(&dbItem).Error
|
||||
if dbItem.ID != 0 {
|
||||
if appType == "mysql" {
|
||||
var (
|
||||
backups []model.BackupRecord
|
||||
mysqls []model.DatabaseMysql
|
||||
)
|
||||
_ = tx.Where("name = ? AND type = ?", dbItem.Name, "mysql").Find(&backups)
|
||||
_ = tx.Where("`from` = ?", "local").Find(&mysqls)
|
||||
for _, item := range backups {
|
||||
isLocal := false
|
||||
for _, mysql := range mysqls {
|
||||
if item.Name == mysql.MysqlName && item.DetailName == mysql.Name {
|
||||
isLocal = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isLocal {
|
||||
_ = tx.Model(&model.BackupRecord{}).Where("id = ?", item.ID).Updates(map[string]interface{}{
|
||||
"name": "remote-" + dbItem.Name,
|
||||
}).Error
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := tx.Debug().Model(&model.DatabaseMysql{}).Where("mysql_name = ? AND `from` != ?", dbItem.Name, "local").Updates(map[string]interface{}{
|
||||
"mysql_name": "remote-" + dbItem.Name,
|
||||
}).Error; err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if err := tx.Debug().Model(&model.Database{}).Where("name = ?", dbItem.Name).Updates(map[string]interface{}{
|
||||
"name": "remote-" + dbItem.Name,
|
||||
}).Error; err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
return database
|
||||
}
|
||||
|
||||
@@ -24,16 +24,17 @@ 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.GET("/installed/check/:key", baseApi.CheckAppInstalled)
|
||||
appRouter.GET("/installed/loadport/:key", baseApi.LoadPort)
|
||||
appRouter.GET("/installed/conninfo/:key", baseApi.LoadConnInfo)
|
||||
appRouter.POST("/installed/check", baseApi.CheckAppInstalled)
|
||||
appRouter.POST("/installed/loadport", baseApi.LoadPort)
|
||||
appRouter.POST("/installed/conninfo", 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.GET("/installed/conf/:key", baseApi.GetDefaultConfig)
|
||||
appRouter.POST("/installed/conf", baseApi.GetDefaultConfig)
|
||||
appRouter.GET("/installed/params/:appInstallId", baseApi.GetParams)
|
||||
appRouter.POST("/installed/params/update", baseApi.UpdateInstalled)
|
||||
appRouter.POST("/installed/ignore", baseApi.IgnoreUpgrade)
|
||||
|
||||
@@ -17,7 +17,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
cmdRouter.POST("", baseApi.CreateMysql)
|
||||
cmdRouter.GET("load/:from", baseApi.LoadDBFromRemote)
|
||||
cmdRouter.POST("load", 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.GET("/variables", baseApi.LoadVariables)
|
||||
cmdRouter.GET("/status", baseApi.LoadStatus)
|
||||
cmdRouter.GET("/baseinfo", baseApi.LoadBaseinfo)
|
||||
cmdRouter.GET("/remote", baseApi.LoadRemoteAccess)
|
||||
cmdRouter.POST("/variables", baseApi.LoadVariables)
|
||||
cmdRouter.POST("/status", baseApi.LoadStatus)
|
||||
cmdRouter.POST("/baseinfo", baseApi.LoadBaseinfo)
|
||||
cmdRouter.POST("/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("/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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ 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)
|
||||
@@ -54,7 +55,6 @@ 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)
|
||||
|
||||
@@ -34,6 +34,7 @@ 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)
|
||||
|
||||
@@ -53,6 +53,7 @@ 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)
|
||||
|
||||
@@ -141,6 +141,35 @@ 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
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/mozillazg/go-pinyin"
|
||||
)
|
||||
|
||||
func CompareVersion(version1 string, version2 string) bool {
|
||||
@@ -23,6 +24,17 @@ func CompareVersion(version1 string, version2 string) bool {
|
||||
version1s := strings.Split(version1, ".")
|
||||
version2s := strings.Split(version2, ".")
|
||||
|
||||
if len(version2s) > len(version1s) {
|
||||
for i := 0; i < len(version2s)-len(version1s); i++ {
|
||||
version1s = append(version1s, "0")
|
||||
}
|
||||
}
|
||||
if len(version1s) > len(version2s) {
|
||||
for i := 0; i < len(version1s)-len(version2s); i++ {
|
||||
version2s = append(version2s, "0")
|
||||
}
|
||||
}
|
||||
|
||||
n := min(len(version1s), len(version2s))
|
||||
re := regexp.MustCompile("[0-9]+")
|
||||
for i := 0; i < n; i++ {
|
||||
@@ -113,6 +125,13 @@ 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) {
|
||||
@@ -148,6 +167,19 @@ func LoadSizeUnit(value float64) string {
|
||||
return fmt.Sprintf("%v", value)
|
||||
}
|
||||
|
||||
func LoadSizeUnit2F(value float64) string {
|
||||
if value > 1073741824 {
|
||||
return fmt.Sprintf("%.2fG", value/1073741824)
|
||||
}
|
||||
if value > 1048576 {
|
||||
return fmt.Sprintf("%.2fM", value/1048576)
|
||||
}
|
||||
if value > 1024 {
|
||||
return fmt.Sprintf("%.2fK", value/1024)
|
||||
}
|
||||
return fmt.Sprintf("%.2f", value)
|
||||
}
|
||||
|
||||
func LoadTimeZone() string {
|
||||
loc := time.Now().Location()
|
||||
if _, err := time.LoadLocation(loc.String()); err != nil {
|
||||
@@ -173,3 +205,17 @@ 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, "")
|
||||
}
|
||||
|
||||
@@ -42,7 +42,10 @@ func (c Client) ListAllContainers() ([]types.Container, error) {
|
||||
}
|
||||
|
||||
func (c Client) ListContainersByName(names []string) ([]types.Container, error) {
|
||||
var options types.ContainerListOptions
|
||||
var (
|
||||
options types.ContainerListOptions
|
||||
res []types.Container
|
||||
)
|
||||
options.All = true
|
||||
if len(names) > 0 {
|
||||
var array []filters.KeyValuePair
|
||||
@@ -55,7 +58,12 @@ func (c Client) ListContainersByName(names []string) ([]types.Container, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return containers, nil
|
||||
for _, container := range containers {
|
||||
if container.Names[0] == "/"+names[0] {
|
||||
res = append(res, container)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c Client) CreateNetwork(name string) error {
|
||||
|
||||
@@ -8,16 +8,23 @@ 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 "", errors.New("it is not possible to encrypt an empty string.")
|
||||
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
|
||||
}
|
||||
key := global.CONF.System.EncryptKey
|
||||
pass := []byte(text)
|
||||
@@ -31,7 +38,14 @@ func StringEncrypt(text string) (string, error) {
|
||||
|
||||
func StringDecrypt(text string) (string, error) {
|
||||
if len(text) == 0 {
|
||||
return "", errors.New("it is not possible to decrypt an empty string.")
|
||||
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
|
||||
}
|
||||
key := global.CONF.System.EncryptKey
|
||||
bytesPass, err := base64.StdEncoding.DecodeString(text)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -518,6 +518,13 @@ func (f FileOp) Decompress(srcFile string, dst string, cType CompressType) error
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
parentDir := path.Dir(filePath)
|
||||
if !f.Stat(parentDir) {
|
||||
if err := f.Fs.MkdirAll(parentDir, info.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
fr, err := archFile.Open()
|
||||
if err != nil {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -23,6 +24,8 @@ 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"`
|
||||
@@ -77,6 +80,8 @@ 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),
|
||||
}
|
||||
@@ -208,6 +213,8 @@ 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 {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"github.com/spf13/afero"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -75,3 +76,36 @@ 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
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ 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"`
|
||||
APPName string `json:"appName"`
|
||||
IsUsed bool `json:"isUsed"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type Forward struct {
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
|
||||
)
|
||||
|
||||
@@ -28,11 +27,8 @@ type MysqlClient interface {
|
||||
|
||||
func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
|
||||
if conn.From == "local" {
|
||||
if cmd.CheckIllegal(conn.Address, conn.Username, conn.Password) {
|
||||
return nil, buserr.New(constant.ErrCmdIllegal)
|
||||
}
|
||||
connArgs := []string{"exec", conn.Address, "mysql", "-u" + conn.Username, "-p" + conn.Password, "-e"}
|
||||
return client.NewLocal(connArgs, conn.Address, conn.Password, conn.From), nil
|
||||
return client.NewLocal(connArgs, conn.Address, conn.Password, conn.Database), nil
|
||||
}
|
||||
|
||||
connArgs := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8", conn.Username, conn.Password, conn.Address, conn.Port)
|
||||
@@ -52,7 +48,7 @@ func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
|
||||
|
||||
return client.NewRemote(client.Remote{
|
||||
Client: db,
|
||||
From: conn.From,
|
||||
Database: conn.Database,
|
||||
User: conn.Username,
|
||||
Password: conn.Password,
|
||||
Address: conn.Address,
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
)
|
||||
|
||||
type DBInfo struct {
|
||||
From string `json:"from"`
|
||||
Database string `json:"database"`
|
||||
Address string `json:"address"`
|
||||
Port uint `json:"port"`
|
||||
Username string `json:"userName"`
|
||||
@@ -85,3 +92,25 @@ var formatMap = map[string]string{
|
||||
"gbk": "gbk_chinese_ci",
|
||||
"big5": "big5_chinese_ci",
|
||||
}
|
||||
|
||||
func loadNameByDB(name, version string) string {
|
||||
nameItem := common.ConvertToPinyin(name)
|
||||
if strings.HasPrefix(version, "5.6") {
|
||||
if len(nameItem) <= 16 {
|
||||
return nameItem
|
||||
}
|
||||
return strings.TrimSuffix(nameItem[:10], "_") + "_" + common.RandStr(5)
|
||||
}
|
||||
if len(nameItem) <= 32 {
|
||||
return nameItem
|
||||
}
|
||||
return strings.TrimSuffix(nameItem[:25], "_") + "_" + common.RandStr(5)
|
||||
}
|
||||
|
||||
func randomPassword(user string) string {
|
||||
passwdItem := user
|
||||
if len(user) > 6 {
|
||||
passwdItem = user[:6]
|
||||
}
|
||||
return passwdItem + "@" + common.RandStrAndNum(8)
|
||||
}
|
||||
|
||||
@@ -14,31 +14,30 @@ 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
|
||||
From string
|
||||
Database string
|
||||
Password string
|
||||
ContainerName string
|
||||
}
|
||||
|
||||
func NewLocal(command []string, containerName, password, from string) *Local {
|
||||
return &Local{PrefixCommand: command, ContainerName: containerName, Password: password, From: from}
|
||||
func NewLocal(command []string, containerName, password, database string) *Local {
|
||||
return &Local{PrefixCommand: command, ContainerName: containerName, Password: password, Database: database}
|
||||
}
|
||||
|
||||
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(err.Error(), "ERROR 1007") {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "error 1007") {
|
||||
return buserr.New(constant.ErrDatabaseIsExist)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.CreateUser(info); err != nil {
|
||||
if err := r.CreateUser(info, true); err != nil {
|
||||
_ = r.ExecSQL(fmt.Sprintf("drop database if exists `%s`", info.Name), info.Timeout)
|
||||
return err
|
||||
}
|
||||
@@ -46,7 +45,7 @@ func (r *Local) Create(info CreateInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Local) CreateUser(info CreateInfo) error {
|
||||
func (r *Local) CreateUser(info CreateInfo, withDeleteDB bool) error {
|
||||
var userlist []string
|
||||
if strings.Contains(info.Permission, ",") {
|
||||
ips := strings.Split(info.Permission, ",")
|
||||
@@ -61,7 +60,7 @@ func (r *Local) CreateUser(info CreateInfo) 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(err.Error(), "ERROR 1396") {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "error 1396") {
|
||||
return buserr.New(constant.ErrUserIsExist)
|
||||
}
|
||||
_ = r.Delete(DeleteInfo{
|
||||
@@ -79,6 +78,8 @@ func (r *Local) CreateUser(info CreateInfo) 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{
|
||||
@@ -147,7 +148,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 WITH mysql_native_password 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
|
||||
@@ -164,7 +165,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 with mysql_native_password BY '%s';", host, info.Password)
|
||||
passwordRootChangeCMD = fmt.Sprintf("alter user 'root'@'%s' identified by '%s';", host, info.Password)
|
||||
}
|
||||
if err := r.ExecSQL(passwordRootChangeCMD, info.Timeout); err != nil {
|
||||
return err
|
||||
@@ -201,7 +202,7 @@ func (r *Local) ChangeAccess(info AccessChangeInfo) error {
|
||||
Password: info.Password,
|
||||
Permission: info.Permission,
|
||||
Timeout: info.Timeout,
|
||||
}); err != nil {
|
||||
}, false); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ExecSQL("flush privileges", 300); err != nil {
|
||||
@@ -272,11 +273,12 @@ func (r *Local) SyncDB(version string) ([]SyncDBInfo, error) {
|
||||
continue
|
||||
}
|
||||
dataItem := SyncDBInfo{
|
||||
Name: parts[0],
|
||||
From: r.From,
|
||||
Format: parts[1],
|
||||
Name: parts[0],
|
||||
From: "local",
|
||||
MysqlName: r.Database,
|
||||
Format: parts[1],
|
||||
}
|
||||
userLines, err := r.ExecSQLForRows(fmt.Sprintf("SELECT USER,HOST FROM mysql.DB WHERE DB = '%s'", parts[0]), 300)
|
||||
userLines, err := r.ExecSQLForRows(fmt.Sprintf("select user,host from mysql.db where db = '%s'", parts[0]), 300)
|
||||
if err != nil {
|
||||
return datas, err
|
||||
}
|
||||
@@ -305,18 +307,19 @@ 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: parts[0],
|
||||
Password: common.RandStr(16),
|
||||
Username: dataItem.Username,
|
||||
Password: dataItem.Password,
|
||||
Permission: "%",
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
}, false); err != nil {
|
||||
global.LOG.Errorf("sync from remote server failed, err: create user failed %v", err)
|
||||
}
|
||||
dataItem.Username = parts[0]
|
||||
dataItem.Permission = "%"
|
||||
} else {
|
||||
if isLocal {
|
||||
|
||||
@@ -12,14 +12,13 @@ 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
|
||||
From string
|
||||
Database string
|
||||
User string
|
||||
Password string
|
||||
Address string
|
||||
@@ -33,13 +32,13 @@ 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(err.Error(), "ERROR 1007") {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "error 1007") {
|
||||
return buserr.New(constant.ErrDatabaseIsExist)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.CreateUser(info); err != nil {
|
||||
if err := r.CreateUser(info, true); err != nil {
|
||||
_ = r.ExecSQL(fmt.Sprintf("drop database if exists `%s`", info.Name), info.Timeout)
|
||||
return err
|
||||
}
|
||||
@@ -47,7 +46,7 @@ func (r *Remote) Create(info CreateInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Remote) CreateUser(info CreateInfo) error {
|
||||
func (r *Remote) CreateUser(info CreateInfo, withDeleteDB bool) error {
|
||||
var userlist []string
|
||||
if strings.Contains(info.Permission, ",") {
|
||||
ips := strings.Split(info.Permission, ",")
|
||||
@@ -62,16 +61,18 @@ func (r *Remote) CreateUser(info CreateInfo) error {
|
||||
|
||||
for _, user := range userlist {
|
||||
if err := r.ExecSQL(fmt.Sprintf("create user %s identified by '%s';", user, info.Password), info.Timeout); err != nil {
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Version: info.Version,
|
||||
Username: info.Username,
|
||||
Permission: info.Permission,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
if strings.Contains(err.Error(), "ERROR 1396") {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "error 1396") {
|
||||
return buserr.New(constant.ErrUserIsExist)
|
||||
}
|
||||
if withDeleteDB {
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Version: info.Version,
|
||||
Username: info.Username,
|
||||
Permission: info.Permission,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
}
|
||||
return err
|
||||
}
|
||||
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to %s", info.Name, user)
|
||||
@@ -80,15 +81,19 @@ func (r *Remote) CreateUser(info CreateInfo) 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{
|
||||
Name: info.Name,
|
||||
Version: info.Version,
|
||||
Username: info.Username,
|
||||
Permission: info.Permission,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
if withDeleteDB {
|
||||
_ = r.Delete(DeleteInfo{
|
||||
Name: info.Name,
|
||||
Version: info.Version,
|
||||
Username: info.Username,
|
||||
Permission: info.Permission,
|
||||
ForceDelete: true,
|
||||
Timeout: 300})
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -148,7 +153,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 WITH mysql_native_password 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 +170,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 with mysql_native_password BY '%s';", host, info.Password)
|
||||
passwordRootChangeCMD = fmt.Sprintf("alter user 'root'@'%s' identified by '%s';", host, info.Password)
|
||||
}
|
||||
if err := r.ExecSQL(passwordRootChangeCMD, info.Timeout); err != nil {
|
||||
return err
|
||||
@@ -202,7 +207,7 @@ func (r *Remote) ChangeAccess(info AccessChangeInfo) error {
|
||||
Password: info.Password,
|
||||
Permission: info.Permission,
|
||||
Timeout: info.Timeout,
|
||||
}); err != nil {
|
||||
}, false); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ExecSQL("flush privileges", 300); err != nil {
|
||||
@@ -263,7 +268,7 @@ func (r *Remote) Recover(info RecoverInfo) error {
|
||||
|
||||
func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) {
|
||||
var datas []SyncDBInfo
|
||||
rows, err := r.Client.Query("SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME FROM information_schema.SCHEMATA")
|
||||
rows, err := r.Client.Query("select schema_name, default_character_set_name from information_schema.SCHEMATA")
|
||||
if err != nil {
|
||||
return datas, err
|
||||
}
|
||||
@@ -279,11 +284,11 @@ func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) {
|
||||
}
|
||||
dataItem := SyncDBInfo{
|
||||
Name: dbName,
|
||||
From: r.From,
|
||||
MysqlName: r.From,
|
||||
From: "remote",
|
||||
MysqlName: r.Database,
|
||||
Format: charsetName,
|
||||
}
|
||||
userRows, err := r.Client.Query("SELECT USER,HOST FROM mysql.DB WHERE DB = ?", dbName)
|
||||
userRows, err := r.Client.Query("select user,host from mysql.db where db = ?", dbName)
|
||||
if err != nil {
|
||||
return datas, err
|
||||
}
|
||||
@@ -312,18 +317,19 @@ func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) {
|
||||
i++
|
||||
}
|
||||
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: dbName,
|
||||
Password: common.RandStr(16),
|
||||
Username: dataItem.Username,
|
||||
Password: dataItem.Password,
|
||||
Permission: "%",
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
global.LOG.Errorf("sync from remote server failed, err: create user failed %v", err)
|
||||
}, false); err != nil {
|
||||
return datas, fmt.Errorf("sync db from remote server failed, err: create user failed %v", err)
|
||||
}
|
||||
dataItem.Username = dbName
|
||||
dataItem.Permission = "%"
|
||||
} else {
|
||||
if isLocal {
|
||||
|
||||
@@ -3,11 +3,12 @@ package cmd
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/cmd/server/app"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -31,6 +32,10 @@ var initCmd = &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "初始化应用",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if !isRoot() {
|
||||
fmt.Println("请使用 sudo 1pctl app init 或者切换到 root 用户")
|
||||
return nil
|
||||
}
|
||||
if len(args) > 0 {
|
||||
appKey = args[0]
|
||||
if len(args) > 1 {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -22,6 +24,10 @@ var resetMFACmd = &cobra.Command{
|
||||
Use: "mfa",
|
||||
Short: "取消 1Panel 两步验证",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if !isRoot() {
|
||||
fmt.Println("请使用 sudo 1pctl reset mfa 或者切换到 root 用户")
|
||||
return nil
|
||||
}
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -34,6 +40,10 @@ var resetSSLCmd = &cobra.Command{
|
||||
Use: "https",
|
||||
Short: "取消 1Panel https 方式登录",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if !isRoot() {
|
||||
fmt.Println("请使用 sudo 1pctl reset https 或者切换到 root 用户")
|
||||
return nil
|
||||
}
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -46,6 +56,10 @@ var resetEntranceCmd = &cobra.Command{
|
||||
Use: "entrance",
|
||||
Short: "取消 1Panel 安全入口",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if !isRoot() {
|
||||
fmt.Println("请使用 sudo 1pctl reset entrance 或者切换到 root 用户")
|
||||
return nil
|
||||
}
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -58,6 +72,10 @@ var resetBindIpsCmd = &cobra.Command{
|
||||
Use: "ips",
|
||||
Short: "取消 1Panel 授权 IP 限制",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if !isRoot() {
|
||||
fmt.Println("请使用 sudo 1pctl reset ips 或者切换到 root 用户")
|
||||
return nil
|
||||
}
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -70,6 +88,10 @@ var resetDomainCmd = &cobra.Command{
|
||||
Use: "domain",
|
||||
Short: "取消 1Panel 访问域名绑定",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if !isRoot() {
|
||||
fmt.Println("请使用 sudo 1pctl reset domain 或者切换到 root 用户")
|
||||
return nil
|
||||
}
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user