From 550872a564d5935330e09d8469f2428d9bde4a98 Mon Sep 17 00:00:00 2001
From: zhengkunwang223 <31820853+zhengkunwang223@users.noreply.github.com>
Date: Tue, 11 Apr 2023 14:38:27 +0800
Subject: [PATCH] =?UTF-8?q?fix:=20=E8=A7=A3=E5=86=B3=E5=AE=89=E8=A3=85?=
=?UTF-8?q?=E5=BA=94=E7=94=A8=E9=94=81=E5=BA=93=E7=9A=84=E9=97=AE=E9=A2=98?=
=?UTF-8?q?=20(#576)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/app/repo/app_install.go | 5 +-
backend/app/service/app.go | 102 +++++++++++-------
backend/app/service/app_utils.go | 30 ++++--
backend/app/service/database_mysql.go | 27 +++--
backend/app/service/website.go | 27 +++--
backend/app/service/website_utils.go | 2 +-
backend/constant/errs.go | 1 +
backend/i18n/lang/en.yaml | 1 +
backend/i18n/lang/zh.yaml | 1 +
.../views/website/website/delete/index.vue | 2 +-
10 files changed, 134 insertions(+), 64 deletions(-)
diff --git a/backend/app/repo/app_install.go b/backend/app/repo/app_install.go
index 5c6d44d28..e863eebd7 100644
--- a/backend/app/repo/app_install.go
+++ b/backend/app/repo/app_install.go
@@ -3,6 +3,7 @@ package repo
import (
"context"
"encoding/json"
+ "gorm.io/gorm/clause"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
@@ -107,11 +108,11 @@ func (a *AppInstallRepo) GetFirstByCtx(ctx context.Context, opts ...DBOption) (m
func (a *AppInstallRepo) Create(ctx context.Context, install *model.AppInstall) error {
db := getTx(ctx).Model(&model.AppInstall{})
- return db.Create(&install).Error
+ return db.Omit(clause.Associations).Create(&install).Error
}
func (a *AppInstallRepo) Save(ctx context.Context, install *model.AppInstall) error {
- return getTx(ctx).Save(&install).Error
+ return getTx(ctx).Omit(clause.Associations).Save(&install).Error
}
func (a *AppInstallRepo) DeleteBy(opts ...DBOption) error {
diff --git a/backend/app/service/app.go b/backend/app/service/app.go
index 2b2facbdc..eb617b2f2 100644
--- a/backend/app/service/app.go
+++ b/backend/app/service/app.go
@@ -224,34 +224,42 @@ func (a AppService) GetAppDetailByID(id uint) (*response.AppDetailDTO, error) {
return res, nil
}
-func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error) {
- if err := docker.CreateDefaultDockerNetwork(); err != nil {
- return nil, buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)
+func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (appInstall *model.AppInstall, err error) {
+ if err = docker.CreateDefaultDockerNetwork(); err != nil {
+ err = buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)
+ return
}
if list, _ := appInstallRepo.ListBy(commonRepo.WithByName(req.Name)); len(list) > 0 {
- return nil, buserr.New(constant.ErrNameIsExist)
+ err = buserr.New(constant.ErrNameIsExist)
+ return
}
- httpPort, err := checkPort("PANEL_APP_PORT_HTTP", req.Params)
+ var (
+ httpPort int
+ httpsPort int
+ appDetail model.AppDetail
+ app model.App
+ )
+ httpPort, err = checkPort("PANEL_APP_PORT_HTTP", req.Params)
+ if err != nil {
+ return
+ }
+ httpsPort, err = checkPort("PANEL_APP_PORT_HTTPS", req.Params)
+ if err != nil {
+ return
+ }
+ appDetail, err = appDetailRepo.GetFirst(commonRepo.WithByID(req.AppDetailId))
+ if err != nil {
+ return
+ }
+ app, err = appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
if err != nil {
return nil, err
}
- httpsPort, err := checkPort("PANEL_APP_PORT_HTTPS", req.Params)
- if err != nil {
- return nil, err
- }
- appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(req.AppDetailId))
- if err != nil {
- return nil, err
- }
- app, err := appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
- if err != nil {
- return nil, err
- }
- if err := checkRequiredAndLimit(app); err != nil {
- return nil, err
+ if err = checkRequiredAndLimit(app); err != nil {
+ return
}
- appInstall := model.AppInstall{
+ appInstall = &model.AppInstall{
Name: req.Name,
AppId: appDetail.AppId,
AppDetailId: appDetail.ID,
@@ -262,13 +270,14 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
App: app,
}
composeMap := make(map[string]interface{})
- if err := yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
- return nil, err
+ if err = yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
+ return
}
value, ok := composeMap["services"]
if !ok {
- return nil, buserr.New("")
+ err = buserr.New("")
+ return
}
servicesMap := value.(map[string]interface{})
changeKeys := make(map[string]string, len(servicesMap))
@@ -289,35 +298,50 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
servicesMap[v] = servicesMap[k]
delete(servicesMap, k)
}
- composeByte, err := yaml.Marshal(composeMap)
+
+ var (
+ composeByte []byte
+ paramByte []byte
+ )
+
+ composeByte, err = yaml.Marshal(composeMap)
if err != nil {
- return nil, err
+ return
}
appInstall.DockerCompose = string(composeByte)
- if err := copyAppData(app.Key, appDetail.Version, req.Name, req.Params, app.Resource == constant.AppResourceLocal); err != nil {
- return nil, err
+ defer func() {
+ if err != nil {
+ hErr := handleAppInstallErr(ctx, appInstall)
+ if hErr != nil {
+ global.LOG.Errorf("delete app dir error %s", hErr.Error())
+ }
+ }
+ }()
+
+ if err = copyAppData(app.Key, appDetail.Version, req.Name, req.Params, app.Resource == constant.AppResourceLocal); err != nil {
+ return
}
fileOp := files.NewFileOp()
- if err := fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(string(composeByte)), 0775); err != nil {
- return nil, err
+ if err = fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(string(composeByte)), 0775); err != nil {
+ return
}
- paramByte, err := json.Marshal(req.Params)
+ paramByte, err = json.Marshal(req.Params)
if err != nil {
- return nil, err
+ return
}
appInstall.Env = string(paramByte)
- if err := appInstallRepo.Create(ctx, &appInstall); err != nil {
- return nil, err
+ if err = appInstallRepo.Create(ctx, appInstall); err != nil {
+ return
}
- if err := createLink(ctx, app, &appInstall, req.Params); err != nil {
- return nil, err
+ if err = createLink(ctx, app, appInstall, req.Params); err != nil {
+ return
}
- if err := upAppPre(app, appInstall); err != nil {
- return nil, err
+ if err = upAppPre(app, appInstall); err != nil {
+ return
}
- go upApp(ctx, appInstall)
+ go upApp(appInstall)
go updateToolApp(appInstall)
ports := []int{appInstall.HttpPort}
if appInstall.HttpsPort > 0 {
@@ -326,7 +350,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
go func() {
_ = OperateFirewallPort(nil, ports)
}()
- return &appInstall, nil
+ return
}
func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
diff --git a/backend/app/service/app_utils.go b/backend/app/service/app_utils.go
index 007f9421f..287613666 100644
--- a/backend/app/service/app_utils.go
+++ b/backend/app/service/app_utils.go
@@ -129,6 +129,22 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
return nil
}
+func handleAppInstallErr(ctx context.Context, install *model.AppInstall) error {
+ op := files.NewFileOp()
+ appDir := install.GetPath()
+ dir, _ := os.Stat(appDir)
+ if dir != nil {
+ _, _ = compose.Down(install.GetComposePath())
+ if err := op.DeleteDir(appDir); err != nil {
+ return err
+ }
+ }
+ if err := deleteLink(ctx, install, true, true); err != nil {
+ return err
+ }
+ return nil
+}
+
func deleteAppInstall(ctx context.Context, install model.AppInstall, deleteBackup bool, forceDelete bool, deleteDB bool) error {
op := files.NewFileOp()
appDir := install.GetPath()
@@ -381,7 +397,7 @@ func copyAppData(key, version, installName string, params map[string]interface{}
}
// 处理文件夹权限等问题
-func upAppPre(app model.App, appInstall model.AppInstall) error {
+func upAppPre(app model.App, appInstall *model.AppInstall) error {
if app.Key == "nexus" {
dataPath := path.Join(appInstall.GetPath(), "data")
if err := files.NewFileOp().Chown(dataPath, 200, 0); err != nil {
@@ -391,7 +407,7 @@ func upAppPre(app model.App, appInstall model.AppInstall) error {
return nil
}
-func getServiceFromInstall(appInstall model.AppInstall) (service *composeV2.ComposeService, err error) {
+func getServiceFromInstall(appInstall *model.AppInstall) (service *composeV2.ComposeService, err error) {
var (
project *types.Project
envStr string
@@ -412,8 +428,8 @@ func getServiceFromInstall(appInstall model.AppInstall) (service *composeV2.Comp
return
}
-func upApp(ctx context.Context, appInstall model.AppInstall) {
- upProject := func(appInstall model.AppInstall) (err error) {
+func upApp(appInstall *model.AppInstall) {
+ upProject := func(appInstall *model.AppInstall) (err error) {
if err == nil {
var composeService *composeV2.ComposeService
composeService, err = getServiceFromInstall(appInstall)
@@ -437,9 +453,7 @@ func upApp(ctx context.Context, appInstall model.AppInstall) {
}
exist, _ := appInstallRepo.GetFirst(commonRepo.WithByID(appInstall.ID))
if exist.ID > 0 {
- _ = appInstallRepo.Save(context.Background(), &appInstall)
- } else {
- _ = appInstallRepo.Save(ctx, &appInstall)
+ _ = appInstallRepo.Save(context.Background(), appInstall)
}
}
@@ -598,7 +612,7 @@ func getAppInstallByKey(key string) (model.AppInstall, error) {
return appInstall, nil
}
-func updateToolApp(installed model.AppInstall) {
+func updateToolApp(installed *model.AppInstall) {
tooKey, ok := dto.AppToolMap[installed.App.Key]
if !ok {
return
diff --git a/backend/app/service/database_mysql.go b/backend/app/service/database_mysql.go
index bf3c500bc..5984628b3 100644
--- a/backend/app/service/database_mysql.go
+++ b/backend/app/service/database_mysql.go
@@ -93,15 +93,15 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
}
createSql := fmt.Sprintf("create database `%s` default character set %s collate %s", req.Name, req.Format, formatMap[req.Format])
- if err := excuteSql(app.ContainerName, app.Password, createSql); err != nil {
+ if err := excSQL(app.ContainerName, app.Password, createSql); err != nil {
if strings.Contains(err.Error(), "ERROR 1007") {
return nil, buserr.New(constant.ErrDatabaseIsExist)
}
return nil, err
}
tmpPermission := req.Permission
- if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("create user '%s'@'%s' identified by '%s';", req.Username, tmpPermission, req.Password)); err != nil {
- _ = excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", req.Name))
+ if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("create user '%s'@'%s' identified by '%s';", req.Username, tmpPermission, req.Password)); err != nil {
+ _ = excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", req.Name))
if strings.Contains(err.Error(), "ERROR 1396") {
return nil, buserr.New(constant.ErrUserIsExist)
}
@@ -114,7 +114,7 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
if app.Version == "5.7.39" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
}
- if err := excuteSql(app.ContainerName, app.Password, grantStr); err != nil {
+ if err := excSQL(app.ContainerName, app.Password, grantStr); err != nil {
return nil, err
}
@@ -163,10 +163,10 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
return err
}
- if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", db.Username, db.Permission)); err != nil && !req.ForceDelete {
+ if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", db.Username, db.Permission)); err != nil && !req.ForceDelete {
return err
}
- if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop database if exists `%s`", db.Name)); err != nil && !req.ForceDelete {
+ if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database if exists `%s`", db.Name)); err != nil && !req.ForceDelete {
return err
}
global.LOG.Info("execute delete database sql successful, now start to drop uploads and records")
@@ -514,6 +514,21 @@ func excuteSql(containerName, password, command string) error {
return nil
}
+func excSQL(containerName, password, command string) error {
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+ defer cancel()
+ cmd := exec.CommandContext(ctx, "docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
+ err := cmd.Run()
+ if ctx.Err() == context.DeadlineExceeded {
+ return buserr.WithDetail(constant.ErrExecTimeOut, containerName, nil)
+ }
+ if err != nil {
+ stdStr := strings.ReplaceAll(err.Error(), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
+ return errors.New(stdStr)
+ }
+ return nil
+}
+
func updateMyCnf(oldFiles []string, group string, param string, value interface{}) []string {
isOn := false
hasGroup := false
diff --git a/backend/app/service/website.go b/backend/app/service/website.go
index c63452677..da93acf1a 100644
--- a/backend/app/service/website.go
+++ b/backend/app/service/website.go
@@ -168,18 +168,25 @@ func (w WebsiteService) CreateWebsite(ctx context.Context, create request.Websit
switch create.Type {
case constant.Deployment:
if create.AppType == constant.NewApp {
- var req request.AppInstallCreate
+ var (
+ req request.AppInstallCreate
+ install *model.AppInstall
+ )
req.Name = create.AppInstall.Name
req.AppDetailId = create.AppInstall.AppDetailId
req.Params = create.AppInstall.Params
- install, err := NewIAppService().Install(ctx, req)
+ tx, installCtx := getTxAndContext()
+ install, err = NewIAppService().Install(installCtx, req)
if err != nil {
+ tx.Rollback()
return err
}
+ tx.Commit()
website.AppInstallID = install.ID
appInstall = install
} else {
- install, err := appInstallRepo.GetFirst(commonRepo.WithByID(create.AppInstallID))
+ var install model.AppInstall
+ install, err = appInstallRepo.GetFirst(commonRepo.WithByID(create.AppInstallID))
if err != nil {
return err
}
@@ -187,28 +194,34 @@ func (w WebsiteService) CreateWebsite(ctx context.Context, create request.Websit
website.AppInstallID = appInstall.ID
}
case constant.Runtime:
- var err error
runtime, err = runtimeRepo.GetFirst(commonRepo.WithByID(create.RuntimeID))
if err != nil {
return err
}
website.RuntimeID = runtime.ID
if runtime.Resource == constant.ResourceAppstore {
- var req request.AppInstallCreate
+ var (
+ req request.AppInstallCreate
+ nginxInstall model.AppInstall
+ install *model.AppInstall
+ )
reg, _ := regexp.Compile(`[^a-z0-9_-]+`)
req.Name = reg.ReplaceAllString(strings.ToLower(create.PrimaryDomain), "")
req.AppDetailId = create.AppInstall.AppDetailId
req.Params = create.AppInstall.Params
req.Params["IMAGE_NAME"] = runtime.Image
- nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
+ nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
req.Params["PANEL_WEBSITE_DIR"] = path.Join(nginxInstall.GetPath(), "/www")
- install, err := NewIAppService().Install(ctx, req)
+ tx, installCtx := getTxAndContext()
+ install, err = NewIAppService().Install(installCtx, req)
if err != nil {
+ tx.Rollback()
return err
}
+ tx.Commit()
website.AppInstallID = install.ID
appInstall = install
}
diff --git a/backend/app/service/website_utils.go b/backend/app/service/website_utils.go
index e37cebcdd..3fdb4e00b 100644
--- a/backend/app/service/website_utils.go
+++ b/backend/app/service/website_utils.go
@@ -105,7 +105,7 @@ func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website,
if err := fileOp.CreateDir(path.Join(siteFolder, "ssl"), 0755); err != nil {
return err
}
- if runtime.Type == constant.RuntimePHP && runtime.Resource == constant.ResourceLocal {
+ if website.Type == constant.Runtime && runtime.Type == constant.RuntimePHP && runtime.Resource == constant.ResourceLocal {
phpPoolDir := path.Join(siteFolder, "php-pool")
if err := fileOp.CreateDir(phpPoolDir, 0755); err != nil {
return err
diff --git a/backend/constant/errs.go b/backend/constant/errs.go
index dc8670b30..8ec738afc 100644
--- a/backend/constant/errs.go
+++ b/backend/constant/errs.go
@@ -91,6 +91,7 @@ var (
var (
ErrUserIsExist = "ErrUserIsExist"
ErrDatabaseIsExist = "ErrDatabaseIsExist"
+ ErrExecTimeOut = "ErrExecTimeOut"
)
// redis
diff --git a/backend/i18n/lang/en.yaml b/backend/i18n/lang/en.yaml
index 0c93a9b12..6db5d9728 100644
--- a/backend/i18n/lang/en.yaml
+++ b/backend/i18n/lang/en.yaml
@@ -52,6 +52,7 @@ ErrEmailIsExist: 'Email is already exist'
#mysql
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 {{ .detail }} container"
#redis
ErrTypeOfRedis: "The recovery file type does not match the current persistence mode. Modify the file type and try again"
diff --git a/backend/i18n/lang/zh.yaml b/backend/i18n/lang/zh.yaml
index 85f49cb76..108b46871 100644
--- a/backend/i18n/lang/zh.yaml
+++ b/backend/i18n/lang/zh.yaml
@@ -52,6 +52,7 @@ ErrEmailIsExist: '邮箱已存在'
#mysql
ErrUserIsExist: "当前用户已存在,请重新输入"
ErrDatabaseIsExist: "当前数据库已存在,请重新输入"
+ErrExecTimeOut: "SQL 执行超时,请检查{{ .detail }}容器"
#redis
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
diff --git a/frontend/src/views/website/website/delete/index.vue b/frontend/src/views/website/website/delete/index.vue
index 79c86cda7..a4fda5d2c 100644
--- a/frontend/src/views/website/website/delete/index.vue
+++ b/frontend/src/views/website/website/delete/index.vue
@@ -23,7 +23,7 @@
{{ $t('website.deleteAppHelper') }}
-
+
{{ $t('website.deleteRuntimeHelper') }}