mirror of
https://github.com/XShengTech/MEGREZ.git
synced 2026-01-14 00:57:17 +08:00
[Feat] ✨ Add Force Delete Instance Button at AdminInstancesList Page #11
This commit is contained in:
parent
249f99e5d9
commit
8104773f40
@ -90,6 +90,9 @@ export default {
|
||||
AdminInstancesDelete(id) {
|
||||
return ajax(`admin/instances/${id}`, 'delete', {})
|
||||
},
|
||||
AdminInstancesForceDelete(id) {
|
||||
return ajax(`admin/instances/${id}/force`, 'delete', {})
|
||||
},
|
||||
|
||||
AdminUserList(params) {
|
||||
return ajax('admin/users', 'get', { params })
|
||||
|
||||
@ -288,6 +288,7 @@ const instanceMenuItemsTemplate = ref([
|
||||
{ label: '重启实例', icon: 'pi pi-refresh !text-sky-500', command: () => { instanceRestart(instanceDetail.value.id) } },
|
||||
{ label: '调整配置', icon: 'pi pi-sliders-h !text-indigo-500', command: () => { openInstanceModify() } },
|
||||
{ label: '删除实例', icon: 'pi pi-trash !text-red-500', command: () => { openInstanceDelete() } },
|
||||
{ label: '强制删除', icon: 'pi pi-exclamation-triangle !text-red-500', command: () => { openInstanceForceDelete() } }
|
||||
])
|
||||
const instanceMenuItems = ref([])
|
||||
|
||||
@ -410,6 +411,11 @@ const showMenu = (event, instance) => {
|
||||
newItem.disabled = true
|
||||
}
|
||||
break
|
||||
case '强制删除':
|
||||
if (instanceDetail.value.status !== statusFail.value) {
|
||||
newItem.disabled = true
|
||||
}
|
||||
break
|
||||
}
|
||||
instanceMenuItems.value.push(newItem)
|
||||
})
|
||||
@ -517,6 +523,20 @@ const instanceDelete = async (id) => {
|
||||
})
|
||||
}
|
||||
|
||||
const instanceForceDelete = async (id) => {
|
||||
toast.add({ severity: 'info', summary: '强制释放实例', detail: '正在强制释放实例', life: 3000 });
|
||||
setTimeout(() => {
|
||||
getInstances()
|
||||
}, 100);
|
||||
await api.AdminInstancesForceDelete(id, { force: true }).then(async (res) => {
|
||||
toast.add({ severity: 'success', summary: '强制释放实例', detail: '实例已强制释放', life: 3000 });
|
||||
await getInstances()
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
toast.add({ severity: 'error', summary: '强制释放实例失败', detail: err.response.data.msg, life: 3000 });
|
||||
})
|
||||
}
|
||||
|
||||
const openInstanceModify = async () => {
|
||||
instanceConfiguration.value.gpu_count = instanceDetail.value.gpu_count
|
||||
instanceConfiguration.value.volume_size = instanceDetail.value.volume_size
|
||||
@ -595,6 +615,27 @@ const openInstanceDelete = () => {
|
||||
});
|
||||
}
|
||||
|
||||
const openInstanceForceDelete = () => {
|
||||
confirm.require({
|
||||
header: '确认强制删除 实例ID: ' + instanceDetail.value.id,
|
||||
message: '强制实例删除后,数据将无法恢复,请确认删除',
|
||||
icon: 'pi pi-info-circle',
|
||||
rejectProps: {
|
||||
label: '取消',
|
||||
severity: 'secondary',
|
||||
outlined: true
|
||||
},
|
||||
acceptProps: {
|
||||
label: '强制删除',
|
||||
severity: 'danger'
|
||||
},
|
||||
accept: async () => {
|
||||
await instanceForceDelete(instanceDetail.value.id)
|
||||
},
|
||||
reject: () => { }
|
||||
});
|
||||
}
|
||||
|
||||
const instanceModifyLabel = (id, label) => {
|
||||
api.AdminInstancesModifyLabel(id, { label: label }).then(async (res) => {
|
||||
toast.add({ severity: 'success', summary: '修改备注成功', detail: '已保存备注', life: 3000 });
|
||||
|
||||
54
routers/api/v1/admin/instance/forceDelete.go
Normal file
54
routers/api/v1/admin/instance/forceDelete.go
Normal file
@ -0,0 +1,54 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/dispatcher"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func forceDeleteHandler(ctx iris.Context) {
|
||||
l.SetFunction("forceDeleteHandler")
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
instance := models.Instances{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.First(&instance)
|
||||
if result.Error != nil {
|
||||
l.Error("get instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceDeleteError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
status := instance.Status
|
||||
if status != models.InstanceStatusFail {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if instance.FromAction == models.InstanceActionStop || instance.FromAction == models.InstanceActionPause || instance.FromAction == models.InstanceActionRestart {
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(instance.ServerID)), int64(instance.GpuCount))
|
||||
redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(instance.ServerID)), int64(instance.VolumeSize+30))
|
||||
}
|
||||
|
||||
dispatcherData := dispatcher.Data{
|
||||
Type: dispatcher.Delete,
|
||||
Status: status,
|
||||
InstanceID: instance.ID,
|
||||
Force: true,
|
||||
}
|
||||
dispatcher.Push(instance.ServerID, dispatcherData)
|
||||
|
||||
middleware.Success(ctx)
|
||||
|
||||
}
|
||||
@ -34,26 +34,47 @@ func delete(serverID uint, data Data) (err error) {
|
||||
err = instanceController.Delete(&instance)
|
||||
if err != nil {
|
||||
lc.Error("delete instance error: %v", err)
|
||||
ctx := context.Background()
|
||||
if data.Status == models.InstanceStatusRunning || data.Status == models.InstanceStatusPaused {
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(serverID)), int64(-instance.GpuCount))
|
||||
if !data.Force {
|
||||
ctx := context.Background()
|
||||
if data.Status == models.InstanceStatusRunning || data.Status == models.InstanceStatusPaused {
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(serverID)), int64(-instance.GpuCount))
|
||||
}
|
||||
redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(serverID)), int64(-instance.VolumeSize-30))
|
||||
database.DB.Model(&instance).Update("status", models.InstanceStatusFail).Update("from_action", models.InstanceActionDelete)
|
||||
return
|
||||
}
|
||||
redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(serverID)), int64(-instance.VolumeSize-30))
|
||||
database.DB.Model(&instance).Update("status", models.InstanceStatusFail).Update("from_action", models.InstanceActionDelete)
|
||||
}
|
||||
|
||||
if !data.Force {
|
||||
server.VolumeUsed -= instance.VolumeSize + 30
|
||||
if data.Status == models.InstanceStatusRunning || data.Status == models.InstanceStatusPaused {
|
||||
server.GpuUsed -= instance.GpuCount
|
||||
}
|
||||
result = database.DB.Save(&server)
|
||||
if result.Error != nil {
|
||||
lc.Error("save server error: %v", result.Error)
|
||||
return result.Error
|
||||
}
|
||||
lc.Info("delete instance success: %v", instance.ID)
|
||||
} else {
|
||||
if instance.FromAction != models.InstanceActionCreate {
|
||||
server.VolumeUsed -= instance.VolumeSize + 30
|
||||
}
|
||||
if instance.FromAction == models.InstanceActionStop || instance.FromAction == models.InstanceActionPause || instance.FromAction == models.InstanceActionRestart {
|
||||
server.GpuUsed -= instance.GpuCount
|
||||
}
|
||||
result = database.DB.Save(&server)
|
||||
if result.Error != nil {
|
||||
lc.Error("save server error: %v", result.Error)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
result = database.DB.Delete(&instance)
|
||||
if result.Error != nil {
|
||||
lc.Error("force delete instance error: %v", result.Error)
|
||||
}
|
||||
lc.Info("force delete instance success: %v", instance.ID)
|
||||
return
|
||||
}
|
||||
|
||||
server.VolumeUsed -= instance.VolumeSize + 30
|
||||
if data.Status == models.InstanceStatusRunning || data.Status == models.InstanceStatusPaused {
|
||||
server.GpuUsed -= instance.GpuCount
|
||||
}
|
||||
result = database.DB.Save(&server)
|
||||
if result.Error != nil {
|
||||
lc.Error("save server error: %v", result.Error)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
lc.Info("delete instance success: %v", instance.ID)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ type Data struct {
|
||||
VolumeSize *int `json:"volume_size,omitempty"`
|
||||
|
||||
Action instanceController.Action `json:"action,omitempty"`
|
||||
Force bool `json:"force,omitempty"`
|
||||
}
|
||||
|
||||
type Type int
|
||||
|
||||
Loading…
Reference in New Issue
Block a user