From e59072e5a792bedbfc07005ff10b9d193945fa66 Mon Sep 17 00:00:00 2001
From: zhengkunwang <31820853+zhengkunwang223@users.noreply.github.com>
Date: Tue, 6 Aug 2024 14:41:40 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8D=B8=E8=BD=BD=E5=BA=94=E7=94=A8?=
=?UTF-8?q?=E6=94=AF=E6=8C=81=E5=88=A0=E9=99=A4=E9=95=9C=E5=83=8F=20(#6040?=
=?UTF-8?q?)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 1 +
agent/app/dto/request/app.go | 10 +++++
agent/app/service/app_install.go | 9 +++-
agent/app/service/app_utils.go | 41 +++++++++++++++++--
agent/app/service/website.go | 8 +++-
frontend/src/api/interface/app.ts | 1 +
frontend/src/lang/modules/en.ts | 4 ++
frontend/src/lang/modules/tw.ts | 4 +-
frontend/src/lang/modules/zh.ts | 2 +
.../app-store/installed/delete/index.vue | 8 ++++
10 files changed, 81 insertions(+), 7 deletions(-)
diff --git a/.gitignore b/.gitignore
index 2719bf865..0c5231617 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,6 +49,7 @@ core/xpack
core/router/entry_xpack.go
core/server/init_xpack.go
core/utils/xpack/xpack_xpack.go
+xpack
.history/
dist/
diff --git a/agent/app/dto/request/app.go b/agent/app/dto/request/app.go
index c00a6a49c..2da685e7e 100644
--- a/agent/app/dto/request/app.go
+++ b/agent/app/dto/request/app.go
@@ -2,6 +2,7 @@ package request
import (
"github.com/1Panel-dev/1Panel/agent/app/dto"
+ "github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/constant"
)
@@ -73,6 +74,7 @@ type AppInstalledOperate struct {
PullImage bool `json:"pullImage"`
DockerCompose string `json:"dockerCompose"`
TaskID string `json:"taskID"`
+ DeleteImage bool `json:"deleteImage"`
}
type AppInstallUpgrade struct {
@@ -84,6 +86,14 @@ type AppInstallUpgrade struct {
TaskID string `json:"taskID"`
}
+type AppInstallDelete struct {
+ Install model.AppInstall
+ DeleteBackup bool `json:"deleteBackup"`
+ ForceDelete bool `json:"forceDelete"`
+ DeleteDB bool `json:"deleteDB"`
+ DeleteImage bool `json:"deleteImage"`
+}
+
type AppInstalledUpdate struct {
InstallId uint `json:"installId" validate:"required"`
Params map[string]interface{} `json:"params" validate:"required"`
diff --git a/agent/app/service/app_install.go b/agent/app/service/app_install.go
index 61abcfa50..8847fab61 100644
--- a/agent/app/service/app_install.go
+++ b/agent/app/service/app_install.go
@@ -259,7 +259,14 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
}
return syncAppInstallStatus(&install, false)
case constant.Delete:
- if err := deleteAppInstall(install, req.DeleteBackup, req.ForceDelete, req.DeleteDB); err != nil && !req.ForceDelete {
+ deleteReq := request.AppInstallDelete{
+ Install: install,
+ DeleteBackup: req.DeleteBackup,
+ ForceDelete: req.ForceDelete,
+ DeleteDB: req.DeleteDB,
+ DeleteImage: req.DeleteImage,
+ }
+ if err = deleteAppInstall(deleteReq); err != nil && !req.ForceDelete {
return err
}
return nil
diff --git a/agent/app/service/app_utils.go b/agent/app/service/app_utils.go
index 8f55a27a7..029ead10d 100644
--- a/agent/app/service/app_utils.go
+++ b/agent/app/service/app_utils.go
@@ -314,13 +314,14 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
return nil
}
-func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete bool, deleteDB bool) error {
+func deleteAppInstall(deleteReq request.AppInstallDelete) error {
op := files.NewFileOp()
+ install := deleteReq.Install
appDir := install.GetPath()
dir, _ := os.Stat(appDir)
if dir != nil {
out, err := compose.Down(install.GetComposePath())
- if err != nil && !forceDelete {
+ if err != nil && !deleteReq.ForceDelete {
return handleErr(install, err, out)
}
//TODO use task
@@ -328,13 +329,29 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
_, _ = compose.Up(install.GetComposePath())
return err
}
+ if deleteReq.DeleteImage {
+ images, _ := getImages(install)
+ client, err := docker.NewClient()
+ if err != nil {
+ return err
+ }
+ defer client.Close()
+ for _, image := range images {
+ imageID, err := client.GetImageIDByName(image)
+ if err == nil {
+ if err = client.DeleteImage(imageID); err != nil {
+ global.LOG.Errorf("delete image %s error %s", image, err.Error())
+ }
+ }
+ }
+ }
}
tx, ctx := helper.GetTxAndContext()
defer tx.Rollback()
if err := appInstallRepo.Delete(ctx, install); err != nil {
return err
}
- if err := deleteLink(ctx, &install, deleteDB, forceDelete, deleteBackup); err != nil && !forceDelete {
+ if err := deleteLink(ctx, &install, deleteReq.DeleteDB, deleteReq.ForceDelete, deleteReq.DeleteBackup); err != nil && !deleteReq.ForceDelete {
return err
}
@@ -374,7 +391,7 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
if _, err := os.Stat(uploadDir); err == nil {
_ = os.RemoveAll(uploadDir)
}
- if deleteBackup {
+ if deleteReq.DeleteBackup {
localDir, _ := loadLocalDir()
backupDir := path.Join(localDir, fmt.Sprintf("app/%s/%s", install.App.Key, install.Name))
if _, err := os.Stat(backupDir); err == nil {
@@ -691,6 +708,22 @@ func getContainerNames(install model.AppInstall) ([]string, error) {
return containerNames, nil
}
+func getImages(install model.AppInstall) ([]string, error) {
+ envStr, err := coverEnvJsonToStr(install.Env)
+ if err != nil {
+ return nil, err
+ }
+ project, err := composeV2.GetComposeProject(install.Name, install.GetPath(), []byte(install.DockerCompose), []byte(envStr), true)
+ if err != nil {
+ return nil, err
+ }
+ var images []string
+ for _, service := range project.AllServices() {
+ images = append(images, service.Image)
+ }
+ return images, nil
+}
+
func coverEnvJsonToStr(envJson string) (string, error) {
envMap := make(map[string]interface{})
_ = json.Unmarshal([]byte(envJson), &envMap)
diff --git a/agent/app/service/website.go b/agent/app/service/website.go
index 6ec59bf3a..3ba02f65d 100644
--- a/agent/app/service/website.go
+++ b/agent/app/service/website.go
@@ -479,7 +479,13 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
if checkIsLinkApp(website) && req.DeleteApp {
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if appInstall.ID > 0 {
- if err = deleteAppInstall(appInstall, true, req.ForceDelete, true); err != nil && !req.ForceDelete {
+ deleteReq := request.AppInstallDelete{
+ Install: appInstall,
+ ForceDelete: req.ForceDelete,
+ DeleteBackup: true,
+ DeleteDB: true,
+ }
+ if err = deleteAppInstall(deleteReq); err != nil && !req.ForceDelete {
return err
}
}
diff --git a/frontend/src/api/interface/app.ts b/frontend/src/api/interface/app.ts
index f5de7d350..0f84e6d35 100644
--- a/frontend/src/api/interface/app.ts
+++ b/frontend/src/api/interface/app.ts
@@ -188,6 +188,7 @@ export namespace App {
detailId?: number;
forceDelete?: boolean;
deleteBackup?: boolean;
+ deleteImage?: boolean;
}
export interface AppInstalledSearch extends ReqPage {
diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts
index eae10e5ef..9f0ad1897 100644
--- a/frontend/src/lang/modules/en.ts
+++ b/frontend/src/lang/modules/en.ts
@@ -1856,6 +1856,10 @@ const message = {
useCustom: 'Customize docker-compose.yml',
useCustomHelper:
'Using a custom docker-compose.yml file may cause the application upgrade to fail. If it is not necessary, do not check it',
+ diffHelper:
+ 'The left side is the old version, the right side is the new version. After editing, click to save the custom version',
+ deleteImage: 'Delete Image',
+ deleteImageHelper: 'Delete the image related to the application. The task will not stop if deletion fails',
},
website: {
website: 'Website',
diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts
index 70f02afdd..d9bfc5828 100644
--- a/frontend/src/lang/modules/tw.ts
+++ b/frontend/src/lang/modules/tw.ts
@@ -1723,7 +1723,9 @@ const message = {
useDefault: '使用預設版本',
useCustom: '自訂 docker-compose.yml',
useCustomHelper: '使用自訂 docker-compose.yml 文件,可能會導致應用程式升級失敗,如無必要,請勿勾選',
- diffHelper: '左側為舊版本,右側為新版,編輯之後點選使用自訂版本儲存',
+ diffHelper: '左側為舊版本,右側為新版,編輯之後點擊使用自訂版本保存',
+ deleteImage: '刪除鏡像',
+ deleteImageHelper: '刪除應用相關鏡像,刪除失敗任務不會終止',
},
website: {
website: '網站',
diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts
index a53e2c4bd..a545d66d3 100644
--- a/frontend/src/lang/modules/zh.ts
+++ b/frontend/src/lang/modules/zh.ts
@@ -1725,6 +1725,8 @@ const message = {
useCustom: '自定义 docker-compose.yml',
useCustomHelper: '使用自定义 docker-compose.yml 文件,可能会导致应用升级失败,如无必要,请勿勾选',
diffHelper: '左侧为旧版本,右侧为新版,编辑之后点击使用自定义版本保存',
+ deleteImage: '删除镜像',
+ deleteImageHelper: '删除应用相关镜像,删除失败任务不会终止',
},
website: {
website: '网站',
diff --git a/frontend/src/views/app-store/installed/delete/index.vue b/frontend/src/views/app-store/installed/delete/index.vue
index 44296424f..343c9cb79 100644
--- a/frontend/src/views/app-store/installed/delete/index.vue
+++ b/frontend/src/views/app-store/installed/delete/index.vue
@@ -19,6 +19,12 @@
{{ $t('app.deleteBackupHelper') }}
+
+
+
+ {{ $t('app.deleteImageHelper') }}
+
+
@@ -57,6 +63,7 @@ let deleteReq = ref({
deleteBackup: false,
forceDelete: false,
deleteDB: true,
+ deleteImage: true,
});
let open = ref(false);
let loading = ref(false);
@@ -80,6 +87,7 @@ const acceptParams = async (app: App.AppInstallDto) => {
deleteBackup: false,
forceDelete: false,
deleteDB: true,
+ deleteImage: true,
};
deleteInfo.value = '';
deleteReq.value.installId = app.id;