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;