mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-01-06 15:14:29 +08:00
feat: 卸载应用增加任务日志 (#6043)
This commit is contained in:
parent
d005e7b4c9
commit
f2a2c7996f
11 changed files with 201 additions and 127 deletions
|
|
@ -1,7 +1,9 @@
|
|||
package dto
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
)
|
||||
|
||||
type AppDatabase struct {
|
||||
|
|
@ -147,3 +149,10 @@ type AppInstallInfo struct {
|
|||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type DelAppLink struct {
|
||||
Ctx context.Context
|
||||
Task *task.Task
|
||||
Install *model.AppInstall
|
||||
ForceDelete bool
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,10 +88,11 @@ type AppInstallUpgrade struct {
|
|||
|
||||
type AppInstallDelete struct {
|
||||
Install model.AppInstall
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
DeleteDB bool `json:"deleteDB"`
|
||||
DeleteImage bool `json:"deleteImage"`
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
DeleteDB bool `json:"deleteDB"`
|
||||
DeleteImage bool `json:"deleteImage"`
|
||||
TaskID string `json:"taskID"`
|
||||
}
|
||||
|
||||
type AppInstalledUpdate struct {
|
||||
|
|
|
|||
|
|
@ -265,6 +265,7 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
|
|||
ForceDelete: req.ForceDelete,
|
||||
DeleteDB: req.DeleteDB,
|
||||
DeleteImage: req.DeleteImage,
|
||||
TaskID: req.TaskID,
|
||||
}
|
||||
if err = deleteAppInstall(deleteReq); err != nil && !req.ForceDelete {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -134,7 +134,12 @@ var ToolKeys = map[string]uint{
|
|||
|
||||
func createLink(ctx context.Context, installTask *task.Task, app model.App, appInstall *model.AppInstall, params map[string]interface{}) error {
|
||||
deleteAppLink := func(t *task.Task) {
|
||||
_ = deleteLink(ctx, appInstall, true, true, true)
|
||||
del := dto.DelAppLink{
|
||||
Ctx: ctx,
|
||||
Install: appInstall,
|
||||
ForceDelete: true,
|
||||
}
|
||||
_ = deleteLink(del)
|
||||
}
|
||||
var dbConfig dto.AppDatabase
|
||||
if DatabaseKeys[app.Key] > 0 {
|
||||
|
|
@ -315,138 +320,171 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
|||
}
|
||||
|
||||
func deleteAppInstall(deleteReq request.AppInstallDelete) error {
|
||||
op := files.NewFileOp()
|
||||
install := deleteReq.Install
|
||||
op := files.NewFileOp()
|
||||
appDir := install.GetPath()
|
||||
dir, _ := os.Stat(appDir)
|
||||
if dir != nil {
|
||||
out, err := compose.Down(install.GetComposePath())
|
||||
if err != nil && !deleteReq.ForceDelete {
|
||||
return handleErr(install, err, out)
|
||||
}
|
||||
//TODO use task
|
||||
if err = runScript(nil, &install, "uninstall"); err != nil {
|
||||
_, _ = compose.Up(install.GetComposePath())
|
||||
return err
|
||||
}
|
||||
if deleteReq.DeleteImage {
|
||||
images, _ := getImages(install)
|
||||
client, err := docker.NewClient()
|
||||
if err != nil {
|
||||
|
||||
uninstallTask, err := task.NewTaskWithOps(install.Name, task.TaskUninstall, task.TaskScopeApp, deleteReq.TaskID, install.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uninstall := func(t *task.Task) error {
|
||||
dir, _ := os.Stat(appDir)
|
||||
if dir != nil {
|
||||
logStr := i18n.GetMsgByKey("Stop") + i18n.GetMsgByKey("App")
|
||||
t.Log(logStr)
|
||||
|
||||
out, err := compose.Down(install.GetComposePath())
|
||||
if err != nil && !deleteReq.ForceDelete {
|
||||
return handleErr(install, err, out)
|
||||
}
|
||||
t.LogSuccess(logStr)
|
||||
if err = runScript(t, &install, "uninstall"); err != nil {
|
||||
_, _ = compose.Up(install.GetComposePath())
|
||||
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())
|
||||
if deleteReq.DeleteImage {
|
||||
delImageStr := i18n.GetMsgByKey("TaskDelete") + i18n.GetMsgByKey("Image")
|
||||
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 {
|
||||
imgStr := delImageStr + image
|
||||
t.Log(imgStr)
|
||||
|
||||
if err = client.DeleteImage(imageID); err != nil {
|
||||
t.LogFailedWithErr(imgStr, err)
|
||||
continue
|
||||
}
|
||||
t.LogSuccess(delImageStr + image)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tx, ctx := helper.GetTxAndContext()
|
||||
defer tx.Rollback()
|
||||
if err := appInstallRepo.Delete(ctx, install); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deleteLink(ctx, &install, deleteReq.DeleteDB, deleteReq.ForceDelete, deleteReq.DeleteBackup); err != nil && !deleteReq.ForceDelete {
|
||||
return err
|
||||
}
|
||||
tx, ctx := helper.GetTxAndContext()
|
||||
defer tx.Rollback()
|
||||
if err = appInstallRepo.Delete(ctx, install); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if DatabaseKeys[install.App.Key] > 0 {
|
||||
_ = databaseRepo.Delete(ctx, databaseRepo.WithAppInstallID(install.ID))
|
||||
}
|
||||
if deleteReq.DeleteDB {
|
||||
del := dto.DelAppLink{
|
||||
Ctx: ctx,
|
||||
Install: &install,
|
||||
ForceDelete: deleteReq.ForceDelete,
|
||||
Task: uninstallTask,
|
||||
}
|
||||
t.LogWithOps(task.TaskDelete, i18n.GetMsgByKey("Database"))
|
||||
if err = deleteLink(del); err != nil {
|
||||
t.LogFailedWithOps(task.TaskDelete, i18n.GetMsgByKey("Database"), err)
|
||||
if !deleteReq.ForceDelete {
|
||||
return err
|
||||
}
|
||||
}
|
||||
t.LogSuccessWithOps(task.TaskDelete, i18n.GetMsgByKey("Database"))
|
||||
}
|
||||
|
||||
switch install.App.Key {
|
||||
case constant.AppOpenresty:
|
||||
websites, _ := websiteRepo.List()
|
||||
for _, website := range websites {
|
||||
if website.AppInstallID > 0 {
|
||||
websiteAppInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if websiteAppInstall.AppId > 0 {
|
||||
websiteApp, _ := appRepo.GetFirst(commonRepo.WithByID(websiteAppInstall.AppId))
|
||||
if websiteApp.Type == constant.RuntimePHP {
|
||||
go func() {
|
||||
_, _ = compose.Down(websiteAppInstall.GetComposePath())
|
||||
_ = op.DeleteDir(websiteAppInstall.GetPath())
|
||||
}()
|
||||
_ = appInstallRepo.Delete(ctx, websiteAppInstall)
|
||||
if DatabaseKeys[install.App.Key] > 0 {
|
||||
_ = databaseRepo.Delete(ctx, databaseRepo.WithAppInstallID(install.ID))
|
||||
}
|
||||
|
||||
switch install.App.Key {
|
||||
case constant.AppOpenresty:
|
||||
websites, _ := websiteRepo.List()
|
||||
for _, website := range websites {
|
||||
if website.AppInstallID > 0 {
|
||||
websiteAppInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if websiteAppInstall.AppId > 0 {
|
||||
websiteApp, _ := appRepo.GetFirst(commonRepo.WithByID(websiteAppInstall.AppId))
|
||||
if websiteApp.Type == constant.RuntimePHP {
|
||||
go func() {
|
||||
_, _ = compose.Down(websiteAppInstall.GetComposePath())
|
||||
_ = op.DeleteDir(websiteAppInstall.GetPath())
|
||||
}()
|
||||
_ = appInstallRepo.Delete(ctx, websiteAppInstall)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = websiteRepo.DeleteAll(ctx)
|
||||
_ = websiteDomainRepo.DeleteAll(ctx)
|
||||
xpack.RemoveTamper("")
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
_ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name))
|
||||
case constant.AppPostgresql:
|
||||
_ = postgresqlRepo.Delete(ctx, postgresqlRepo.WithByPostgresqlName(install.Name))
|
||||
}
|
||||
_ = websiteRepo.DeleteAll(ctx)
|
||||
_ = websiteDomainRepo.DeleteAll(ctx)
|
||||
xpack.RemoveTamper("")
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
_ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name))
|
||||
case constant.AppPostgresql:
|
||||
_ = postgresqlRepo.Delete(ctx, postgresqlRepo.WithByPostgresqlName(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)
|
||||
}
|
||||
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 {
|
||||
_ = os.RemoveAll(backupDir)
|
||||
_ = 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)
|
||||
}
|
||||
global.LOG.Infof("delete app %s-%s backups successful", install.App.Key, install.Name)
|
||||
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 {
|
||||
t.LogWithOps(task.TaskDelete, i18n.GetMsgByKey("TaskBackup"))
|
||||
_ = os.RemoveAll(backupDir)
|
||||
t.LogSuccessWithOps(task.TaskDelete, i18n.GetMsgByKey("TaskBackup"))
|
||||
}
|
||||
}
|
||||
_ = op.DeleteDir(appDir)
|
||||
tx.Commit()
|
||||
return nil
|
||||
}
|
||||
_ = op.DeleteDir(appDir)
|
||||
tx.Commit()
|
||||
uninstallTask.AddSubTask(task.GetTaskName(install.Name, task.TaskUninstall, task.TaskScopeApp), uninstall, nil)
|
||||
go uninstallTask.Execute()
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, forceDelete bool, deleteBackup bool) error {
|
||||
func deleteLink(del dto.DelAppLink) error {
|
||||
install := del.Install
|
||||
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
if len(resources) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, re := range resources {
|
||||
if deleteDB {
|
||||
switch re.Key {
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
mysqlService := NewIMysqlService()
|
||||
database, _ := mysqlRepo.Get(commonRepo.WithByID(re.ResourceId))
|
||||
if reflect.DeepEqual(database, model.DatabaseMysql{}) {
|
||||
continue
|
||||
}
|
||||
if err := mysqlService.Delete(ctx, dto.MysqlDBDelete{
|
||||
ID: database.ID,
|
||||
ForceDelete: forceDelete,
|
||||
DeleteBackup: deleteBackup,
|
||||
Type: re.Key,
|
||||
Database: database.MysqlName,
|
||||
}); err != nil && !forceDelete {
|
||||
return err
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
pgsqlService := NewIPostgresqlService()
|
||||
database, _ := postgresqlRepo.Get(commonRepo.WithByID(re.ResourceId))
|
||||
if reflect.DeepEqual(database, model.DatabasePostgresql{}) {
|
||||
continue
|
||||
}
|
||||
if err := pgsqlService.Delete(ctx, dto.PostgresqlDBDelete{
|
||||
ID: database.ID,
|
||||
ForceDelete: forceDelete,
|
||||
DeleteBackup: deleteBackup,
|
||||
Type: re.Key,
|
||||
Database: database.PostgresqlName,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
switch re.Key {
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
mysqlService := NewIMysqlService()
|
||||
database, _ := mysqlRepo.Get(commonRepo.WithByID(re.ResourceId))
|
||||
if reflect.DeepEqual(database, model.DatabaseMysql{}) {
|
||||
continue
|
||||
}
|
||||
if err := mysqlService.Delete(del.Ctx, dto.MysqlDBDelete{
|
||||
ID: database.ID,
|
||||
ForceDelete: del.ForceDelete,
|
||||
DeleteBackup: true,
|
||||
Type: re.Key,
|
||||
Database: database.MysqlName,
|
||||
}); err != nil && !del.ForceDelete {
|
||||
return err
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
pgsqlService := NewIPostgresqlService()
|
||||
database, _ := postgresqlRepo.Get(commonRepo.WithByID(re.ResourceId))
|
||||
if reflect.DeepEqual(database, model.DatabasePostgresql{}) {
|
||||
continue
|
||||
}
|
||||
if err := pgsqlService.Delete(del.Ctx, dto.PostgresqlDBDelete{
|
||||
ID: database.ID,
|
||||
ForceDelete: del.ForceDelete,
|
||||
DeleteBackup: true,
|
||||
Type: re.Key,
|
||||
Database: database.PostgresqlName,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
return appInstallResourceRepo.DeleteBy(del.Ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
}
|
||||
|
||||
func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string, error) {
|
||||
|
|
|
|||
|
|
@ -219,3 +219,15 @@ func (t *Task) LogSuccess(msg string) {
|
|||
func (t *Task) LogStart(msg string) {
|
||||
t.Logger.Printf(fmt.Sprintf("%s%s", i18n.GetMsgByKey("Start"), msg))
|
||||
}
|
||||
|
||||
func (t *Task) LogWithOps(operate, msg string) {
|
||||
t.Logger.Printf("%s%s", i18n.GetMsgByKey(operate), msg)
|
||||
}
|
||||
|
||||
func (t *Task) LogSuccessWithOps(operate, msg string) {
|
||||
t.Logger.Printf("%s%s%s", i18n.GetMsgByKey(operate), msg, i18n.GetMsgByKey("Success"))
|
||||
}
|
||||
|
||||
func (t *Task) LogFailedWithOps(operate, msg string, err error) {
|
||||
t.Logger.Printf("%s%s%s : %s ", i18n.GetMsgByKey(operate), msg, i18n.GetMsgByKey("Failed"), err.Error())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -230,4 +230,7 @@ ExecShell: "Execute {{ .name }} Script"
|
|||
PullImage: "Pull Image"
|
||||
Start: "Start"
|
||||
Run: "Run"
|
||||
Stop: 'Stop',
|
||||
Image: 'Image',
|
||||
AppLink: 'Associated Application'
|
||||
|
||||
|
|
|
|||
|
|
@ -232,3 +232,7 @@ ExecShell: "執行 {{ .name }} 腳本"
|
|||
PullImage: "拉取鏡像"
|
||||
Start: "開始"
|
||||
Run: "啟動"
|
||||
Stop: '停止',
|
||||
Image: '鏡像',
|
||||
AppLink: '關聯應用'
|
||||
|
||||
|
|
|
|||
|
|
@ -234,3 +234,6 @@ ExecShell: "执行 {{ .name }} 脚本"
|
|||
PullImage: "拉取镜像"
|
||||
Start: "开始"
|
||||
Run: "启动"
|
||||
Stop: "停止"
|
||||
Image: "镜像"
|
||||
AppLink: "关联应用"
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ export namespace App {
|
|||
forceDelete?: boolean;
|
||||
deleteBackup?: boolean;
|
||||
deleteImage?: boolean;
|
||||
taskID?: string;
|
||||
}
|
||||
|
||||
export interface AppInstalledSearch extends ReqPage {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ const scrollerElement = ref<HTMLElement | null>(null);
|
|||
const minPage = ref(1);
|
||||
const maxPage = ref(1);
|
||||
const open = ref(false);
|
||||
const em = defineEmits(['close']);
|
||||
|
||||
const readReq = reactive({
|
||||
taskID: '',
|
||||
|
|
@ -148,6 +149,7 @@ const changeTail = (fromOutSide: boolean) => {
|
|||
const handleClose = () => {
|
||||
onCloseLog();
|
||||
open.value = false;
|
||||
em('close', open.value);
|
||||
};
|
||||
|
||||
const onCloseLog = async () => {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<TaskLog ref="taskLogRef" @close="handleClose" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { FormInstance } from 'element-plus';
|
||||
|
|
@ -54,23 +55,26 @@ import { onBeforeUnmount, ref } from 'vue';
|
|||
import { App } from '@/api/interface/app';
|
||||
import { InstalledOp } from '@/api/modules/app';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import bus from '../../bus';
|
||||
import TaskLog from '@/components/task-log/index.vue';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
let deleteReq = ref({
|
||||
const deleteReq = ref({
|
||||
operate: 'delete',
|
||||
installId: 0,
|
||||
deleteBackup: false,
|
||||
forceDelete: false,
|
||||
deleteDB: true,
|
||||
deleteImage: true,
|
||||
taskID: '',
|
||||
});
|
||||
let open = ref(false);
|
||||
let loading = ref(false);
|
||||
let deleteHelper = ref('');
|
||||
let deleteInfo = ref('');
|
||||
let appInstallName = ref('');
|
||||
let appType = ref('');
|
||||
const open = ref(false);
|
||||
const loading = ref(false);
|
||||
const deleteHelper = ref('');
|
||||
const deleteInfo = ref('');
|
||||
const appInstallName = ref('');
|
||||
const appType = ref('');
|
||||
const taskLogRef = ref();
|
||||
|
||||
const deleteForm = ref<FormInstance>();
|
||||
const em = defineEmits(['close']);
|
||||
|
|
@ -88,6 +92,7 @@ const acceptParams = async (app: App.AppInstallDto) => {
|
|||
forceDelete: false,
|
||||
deleteDB: true,
|
||||
deleteImage: true,
|
||||
taskID: uuidv4(),
|
||||
};
|
||||
deleteInfo.value = '';
|
||||
deleteReq.value.installId = app.id;
|
||||
|
|
@ -98,16 +103,11 @@ const acceptParams = async (app: App.AppInstallDto) => {
|
|||
};
|
||||
|
||||
const submit = async () => {
|
||||
loading.value = true;
|
||||
InstalledOp(deleteReq.value)
|
||||
.then(() => {
|
||||
handleClose();
|
||||
MsgSuccess(i18n.global.t('commons.msg.deleteSuccess'));
|
||||
bus.emit('update', true);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
InstalledOp(deleteReq.value).then(() => {
|
||||
handleClose();
|
||||
taskLogRef.value.openWithTaskID(deleteReq.value.taskID);
|
||||
bus.emit('update', true);
|
||||
});
|
||||
};
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue