6 Commits

Author SHA1 Message Date
Harry-zklcdc ef93c40361 [Fix] 🐛 Fix GPU Device Error at NoCard Instances #14 2025-02-15 22:00:02 +08:00
Harry-zklcdc 716764a86d [Fix] 🐛 From Status Error at Start Action #12 2025-02-12 23:25:53 +08:00
Harry-zklcdc 44c319698c [Fix] 🐛 Mount Point Error at Container internal #10 2025-02-12 18:32:09 +08:00
Harry-zklcdc 8104773f40 [Feat] Add Force Delete Instance Button at AdminInstancesList Page #11 2025-02-11 00:00:43 +08:00
Harry-zklcdc 249f99e5d9 [Feat] Add Instance Action Fail Status #11 2025-02-10 23:45:19 +08:00
Harry-zklcdc cfbd7d24db [Feat] Add Mount Point Setting 2025-02-09 20:26:54 +08:00
30 changed files with 259 additions and 101 deletions
+1
View File
@@ -12,3 +12,4 @@ redis:
port: 6379 port: 6379
system: system:
verify: false verify: false
mount_dir: /path/to/mount
+3
View File
@@ -90,6 +90,9 @@ export default {
AdminInstancesDelete(id) { AdminInstancesDelete(id) {
return ajax(`admin/instances/${id}`, 'delete', {}) return ajax(`admin/instances/${id}`, 'delete', {})
}, },
AdminInstancesForceDelete(id) {
return ajax(`admin/instances/${id}/force`, 'delete', {})
},
AdminUserList(params) { AdminUserList(params) {
return ajax('admin/users', 'get', { params }) return ajax('admin/users', 'get', { params })
+48 -7
View File
@@ -288,6 +288,7 @@ const instanceMenuItemsTemplate = ref([
{ label: '重启实例', icon: 'pi pi-refresh !text-sky-500', command: () => { instanceRestart(instanceDetail.value.id) } }, { 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-sliders-h !text-indigo-500', command: () => { openInstanceModify() } },
{ label: '删除实例', icon: 'pi pi-trash !text-red-500', command: () => { openInstanceDelete() } }, { label: '删除实例', icon: 'pi pi-trash !text-red-500', command: () => { openInstanceDelete() } },
{ label: '强制删除', icon: 'pi pi-exclamation-triangle !text-red-500', command: () => { openInstanceForceDelete() } }
]) ])
const instanceMenuItems = ref([]) const instanceMenuItems = ref([])
@@ -376,37 +377,42 @@ const showMenu = (event, instance) => {
let newItem = { ...item } let newItem = { ...item }
switch (item.label) { switch (item.label) {
case '无卡模式开机': case '无卡模式开机':
if (instanceDetail.value.cpu_only === true || instanceDetail.value.status !== statusStoped.value) { if (instanceDetail.value.cpu_only === true || instanceDetail.value.status !== statusStoped.value || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '开机': case '开机':
if (instanceDetail.value.status === statusRunning.value || statusIng.indexOf(instanceDetail.value.status) !== -1) { if (instanceDetail.value.status === statusRunning.value || statusIng.indexOf(instanceDetail.value.status) !== -1 || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '关机': case '关机':
if (instanceDetail.value.status === statusStoped.value || statusIng.indexOf(instanceDetail.value.status) !== -1) { if (instanceDetail.value.status === statusStoped.value || statusIng.indexOf(instanceDetail.value.status) !== -1 || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '暂停': case '暂停':
if (instanceDetail.value.status === statusPaused.value || instanceDetail.value.status === statusStoped.value || statusIng.indexOf(instanceDetail.value.status) !== -1) { if (instanceDetail.value.status === statusPaused.value || instanceDetail.value.status === statusStoped.value || statusIng.indexOf(instanceDetail.value.status) !== -1 || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '重启实例': case '重启实例':
if (statusIng.indexOf(instanceDetail.value.status) !== -1) { if (statusIng.indexOf(instanceDetail.value.status) !== -1 || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '调整配置': case '调整配置':
if (instanceDetail.value.status !== statusStoped.value) { if (instanceDetail.value.status !== statusStoped.value || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '删除实例': case '删除实例':
if (instanceDetail.value.status === statusDeleting.value) { if (instanceDetail.value.status === statusDeleting.value || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true
}
break
case '强制删除':
if (instanceDetail.value.status !== statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
@@ -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 () => { const openInstanceModify = async () => {
instanceConfiguration.value.gpu_count = instanceDetail.value.gpu_count instanceConfiguration.value.gpu_count = instanceDetail.value.gpu_count
instanceConfiguration.value.volume_size = instanceDetail.value.volume_size 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) => { const instanceModifyLabel = (id, label) => {
api.AdminInstancesModifyLabel(id, { label: label }).then(async (res) => { api.AdminInstancesModifyLabel(id, { label: label }).then(async (res) => {
toast.add({ severity: 'success', summary: '修改备注成功', detail: '已保存备注', life: 3000 }); toast.add({ severity: 'success', summary: '修改备注成功', detail: '已保存备注', life: 3000 });
+7 -7
View File
@@ -386,37 +386,37 @@ const showMenu = (event, instance) => {
let newItem = { ...item } let newItem = { ...item }
switch (item.label) { switch (item.label) {
case '无卡模式开机': case '无卡模式开机':
if (instanceDetail.value.cpu_only === true || instanceDetail.value.status !== statusStoped.value) { if (instanceDetail.value.cpu_only === true || instanceDetail.value.status !== statusStoped.value || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '开机': case '开机':
if (instanceDetail.value.status === statusRunning.value || statusIng.indexOf(instanceDetail.value.status) !== -1) { if (instanceDetail.value.status === statusRunning.value || statusIng.indexOf(instanceDetail.value.status) !== -1 || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '关机': case '关机':
if (instanceDetail.value.status === statusStoped.value || statusIng.indexOf(instanceDetail.value.status) !== -1) { if (instanceDetail.value.status === statusStoped.value || statusIng.indexOf(instanceDetail.value.status) !== -1 || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '暂停': case '暂停':
if (instanceDetail.value.status === statusPaused.value || instanceDetail.value.status === statusStoped.value || statusIng.indexOf(instanceDetail.value.status) !== -1) { if (instanceDetail.value.status === statusPaused.value || instanceDetail.value.status === statusStoped.value || statusIng.indexOf(instanceDetail.value.status) !== -1 || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '重启实例': case '重启实例':
if (statusIng.indexOf(instanceDetail.value.status) !== -1) { if (statusIng.indexOf(instanceDetail.value.status) !== -1 || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '调整配置': case '调整配置':
if (instanceDetail.value.status !== statusStoped.value) { if (instanceDetail.value.status !== statusStoped.value || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
case '删除实例': case '删除实例':
if (instanceDetail.value.status === statusDeleting.value) { if (instanceDetail.value.status === statusDeleting.value || instanceDetail.value.status === statusFail.value) {
newItem.disabled = true newItem.disabled = true
} }
break break
+24 -12
View File
@@ -8,23 +8,34 @@ import (
) )
type Status int type Status int
type Action int
const ( const (
InstanceFail Status = -1 InstanceStatusFail Status = -1
InstanceRunning Status = 0 InstanceStatusRunning Status = 0
InstancePaused Status = 1 InstanceStatusPaused Status = 1
InstanceStopped Status = 2 InstanceStatusStopped Status = 2
InstanceReady Status = 3 InstanceStatusReady Status = 3
InstanceStarting Status = 4 InstanceStatusStarting Status = 4
InstanceStopping Status = 5 InstanceStatusStopping Status = 5
InstancePausing Status = 6 InstanceStatusPausing Status = 6
InstanceRestarting Status = 7 InstanceStatusRestarting Status = 7
InstanceModifying Status = 8 InstanceStatusModifying Status = 8
InstanceDeleting Status = 9 InstanceStatusDeleting Status = 9
) )
var instanceIngStatus = []Status{InstanceReady, InstanceStarting, InstanceStopping, InstancePausing, InstanceRestarting, InstanceModifying, InstanceDeleting} const (
InstanceActionCreate Action = 1
InstanceActionStart Action = 2
InstanceActionPause Action = 3
InstanceActionStop Action = 4
InstanceActionRestart Action = 5
InstanceActionModify Action = 6
InstanceActionDelete Action = 7
)
var instanceIngStatus = []Status{InstanceStatusReady, InstanceStatusStarting, InstanceStatusStopping, InstanceStatusPausing, InstanceStatusRestarting, InstanceStatusModifying, InstanceStatusDeleting}
type Instances struct { type Instances struct {
ID uint `json:"id" gorm:"primary_key;autoIncrement;index"` ID uint `json:"id" gorm:"primary_key;autoIncrement;index"`
@@ -46,6 +57,7 @@ type Instances struct {
GrafanaAddress string `json:"grafana_address" gorm:"type:varchar(255)"` GrafanaAddress string `json:"grafana_address" gorm:"type:varchar(255)"`
CodeServerAddress string `json:"code_server_address" gorm:"type:varchar(255)"` CodeServerAddress string `json:"code_server_address" gorm:"type:varchar(255)"`
Status Status `json:"status" gorm:"not null"` // Detail in Constants Status Status `json:"status" gorm:"not null"` // Detail in Constants
FromAction Action `json:"from_action"`
Label string `json:"label" gorm:"type:varchar(255)"` Label string `json:"label" gorm:"type:varchar(255)"`
+1 -1
View File
@@ -85,7 +85,7 @@ func addHandler(ctx iris.Context) {
SshPasswd: crypto.Hex(16), SshPasswd: crypto.Hex(16),
Status: models.InstanceReady, Status: models.InstanceStatusReady,
} }
result = database.DB.Create(&instance) result = database.DB.Create(&instance)
if result.Error != nil { if result.Error != nil {
+8 -8
View File
@@ -45,17 +45,17 @@ func controlHandler(ctx iris.Context) {
return return
} }
if req.Action == instanceController.ActionStop && instance.Status != models.InstanceRunning && instance.Status != models.InstancePaused { if req.Action == instanceController.ActionStop && instance.Status != models.InstanceStatusRunning && instance.Status != models.InstanceStatusPaused {
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest) middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
return return
} }
if req.Action == instanceController.ActionPause && instance.Status != models.InstanceRunning { if req.Action == instanceController.ActionPause && instance.Status != models.InstanceStatusRunning {
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest) middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
return return
} }
if req.Action == instanceController.ActionStart && instance.Status != models.InstanceStopped && instance.Status != models.InstancePaused { if req.Action == instanceController.ActionStart && instance.Status != models.InstanceStatusStopped && instance.Status != models.InstanceStatusPaused {
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest) middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
return return
} }
@@ -71,7 +71,7 @@ func controlHandler(ctx iris.Context) {
} }
status := instance.Status status := instance.Status
if status == models.InstanceStopped && (req.Action == instanceController.ActionStart || req.Action == instanceController.ActionRestart) { if status == models.InstanceStatusStopped && (req.Action == instanceController.ActionStart || req.Action == instanceController.ActionRestart) {
remainGpu, err := redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(-instance.GpuCount)).Result() remainGpu, err := redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(-instance.GpuCount)).Result()
if err != nil { if err != nil {
l.Error("incrby gpu num error: %v", err) l.Error("incrby gpu num error: %v", err)
@@ -88,7 +88,7 @@ func controlHandler(ctx iris.Context) {
switch req.Action { switch req.Action {
case instanceController.ActionStart: case instanceController.ActionStart:
result = database.DB.Model(&instance).Update("status", models.InstanceStarting) result = database.DB.Model(&instance).Update("status", models.InstanceStatusStarting)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeInstanceStartError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeInstanceStartError, iris.StatusInternalServerError)
@@ -96,7 +96,7 @@ func controlHandler(ctx iris.Context) {
} }
case instanceController.ActionPause: case instanceController.ActionPause:
result = database.DB.Model(&instance).Update("status", models.InstancePausing) result = database.DB.Model(&instance).Update("status", models.InstanceStatusPausing)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeInstancePauseError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeInstancePauseError, iris.StatusInternalServerError)
@@ -104,7 +104,7 @@ func controlHandler(ctx iris.Context) {
} }
case instanceController.ActionStop: case instanceController.ActionStop:
result = database.DB.Model(&instance).Update("status", models.InstanceStopping) result = database.DB.Model(&instance).Update("status", models.InstanceStatusStopping)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeInstanceStopError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeInstanceStopError, iris.StatusInternalServerError)
@@ -113,7 +113,7 @@ func controlHandler(ctx iris.Context) {
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(instance.GpuCount)) redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(instance.GpuCount))
case instanceController.ActionRestart: case instanceController.ActionRestart:
result = database.DB.Model(&instance).Update("status", models.InstanceRestarting) result = database.DB.Model(&instance).Update("status", models.InstanceStatusRestarting)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeInstanceRestartError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeInstanceRestartError, iris.StatusInternalServerError)
+2 -2
View File
@@ -36,14 +36,14 @@ func deleteHandler(ctx iris.Context) {
return return
} }
result = database.DB.Model(&instance).Update("status", models.InstanceDeleting) result = database.DB.Model(&instance).Update("status", models.InstanceStatusDeleting)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError)
return return
} }
if status == models.InstanceRunning || status == models.InstancePaused { if status == models.InstanceStatusRunning || status == models.InstanceStatusPaused {
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(instance.ServerID)), int64(instance.GpuCount)) 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)) redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(instance.ServerID)), int64(instance.VolumeSize+30))
@@ -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)
}
+2 -2
View File
@@ -57,7 +57,7 @@ func modifyHandler(ctx iris.Context) {
return return
} }
if instance.Status != models.InstanceStopped { if instance.Status != models.InstanceStatusStopped {
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest) middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
return return
} }
@@ -106,7 +106,7 @@ func modifyHandler(ctx iris.Context) {
} }
status := instance.Status status := instance.Status
result = database.DB.Model(&instance).Update("status", models.InstanceModifying) result = database.DB.Model(&instance).Update("status", models.InstanceStatusModifying)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError)
+1
View File
@@ -34,4 +34,5 @@ func InitInstances(party router.Party) {
party.Post("/{id:uint}", middleware.SuperAdminCheck, modifyHandler) party.Post("/{id:uint}", middleware.SuperAdminCheck, modifyHandler)
party.Post("/{id:uint}/label", middleware.SuperAdminCheck, labelHandler) party.Post("/{id:uint}/label", middleware.SuperAdminCheck, labelHandler)
party.Delete("/{id:uint}", middleware.SuperAdminCheck, deleteHandler) party.Delete("/{id:uint}", middleware.SuperAdminCheck, deleteHandler)
party.Delete("/{id:uint}/force", middleware.SuperAdminCheck, forceDeleteHandler)
} }
+1 -1
View File
@@ -80,7 +80,7 @@ func addHandler(ctx iris.Context) {
SshPasswd: crypto.Hex(16), SshPasswd: crypto.Hex(16),
Status: models.InstanceReady, Status: models.InstanceStatusReady,
} }
result = database.DB.Create(&instance) result = database.DB.Create(&instance)
if result.Error != nil { if result.Error != nil {
+8 -8
View File
@@ -51,17 +51,17 @@ func controlHandler(ctx iris.Context) {
return return
} }
if req.Action == instanceController.ActionStop && instance.Status != models.InstanceRunning && instance.Status != models.InstancePaused { if req.Action == instanceController.ActionStop && instance.Status != models.InstanceStatusRunning && instance.Status != models.InstanceStatusPaused {
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest) middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
return return
} }
if req.Action == instanceController.ActionPause && instance.Status != models.InstanceRunning { if req.Action == instanceController.ActionPause && instance.Status != models.InstanceStatusRunning {
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest) middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
return return
} }
if req.Action == instanceController.ActionStart && instance.Status != models.InstanceStopped && instance.Status != models.InstancePaused { if req.Action == instanceController.ActionStart && instance.Status != models.InstanceStatusStopped && instance.Status != models.InstanceStatusPaused {
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest) middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
return return
} }
@@ -77,7 +77,7 @@ func controlHandler(ctx iris.Context) {
} }
status := instance.Status status := instance.Status
if status == models.InstanceStopped && (req.Action == instanceController.ActionStart || req.Action == instanceController.ActionRestart) { if status == models.InstanceStatusStopped && (req.Action == instanceController.ActionStart || req.Action == instanceController.ActionRestart) {
remainGpu, err := redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(-instance.GpuCount)).Result() remainGpu, err := redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(-instance.GpuCount)).Result()
if err != nil { if err != nil {
l.Error("incrby gpu num error: %v", err) l.Error("incrby gpu num error: %v", err)
@@ -94,7 +94,7 @@ func controlHandler(ctx iris.Context) {
switch req.Action { switch req.Action {
case instanceController.ActionStart: case instanceController.ActionStart:
result = database.DB.Model(&instance).Update("status", models.InstanceStarting) result = database.DB.Model(&instance).Update("status", models.InstanceStatusStarting)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeInstanceStartError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeInstanceStartError, iris.StatusInternalServerError)
@@ -102,7 +102,7 @@ func controlHandler(ctx iris.Context) {
} }
case instanceController.ActionPause: case instanceController.ActionPause:
result = database.DB.Model(&instance).Update("status", models.InstancePausing) result = database.DB.Model(&instance).Update("status", models.InstanceStatusPausing)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeInstancePauseError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeInstancePauseError, iris.StatusInternalServerError)
@@ -110,7 +110,7 @@ func controlHandler(ctx iris.Context) {
} }
case instanceController.ActionStop: case instanceController.ActionStop:
result = database.DB.Model(&instance).Update("status", models.InstanceStopping) result = database.DB.Model(&instance).Update("status", models.InstanceStatusStopping)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeInstanceStopError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeInstanceStopError, iris.StatusInternalServerError)
@@ -119,7 +119,7 @@ func controlHandler(ctx iris.Context) {
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(instance.GpuCount)) redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(instance.GpuCount))
case instanceController.ActionRestart: case instanceController.ActionRestart:
result = database.DB.Model(&instance).Update("status", models.InstanceRestarting) result = database.DB.Model(&instance).Update("status", models.InstanceStatusRestarting)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeInstanceRestartError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeInstanceRestartError, iris.StatusInternalServerError)
+2 -2
View File
@@ -40,14 +40,14 @@ func deleteHandler(ctx iris.Context) {
return return
} }
result = database.DB.Model(&instance).Update("status", models.InstanceDeleting) result = database.DB.Model(&instance).Update("status", models.InstanceStatusDeleting)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError)
return return
} }
if status == models.InstanceRunning || status == models.InstancePaused { if status == models.InstanceStatusRunning || status == models.InstanceStatusPaused {
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(instance.ServerID)), int64(instance.GpuCount)) 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)) redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(instance.ServerID)), int64(instance.VolumeSize+30))
+2 -2
View File
@@ -63,7 +63,7 @@ func modifyHandler(ctx iris.Context) {
return return
} }
if instance.Status != models.InstanceStopped { if instance.Status != models.InstanceStatusStopped {
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest) middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
return return
} }
@@ -112,7 +112,7 @@ func modifyHandler(ctx iris.Context) {
} }
status := instance.Status status := instance.Status
result = database.DB.Model(&instance).Update("status", models.InstanceModifying) result = database.DB.Model(&instance).Update("status", models.InstanceStatusModifying)
if result.Error != nil { if result.Error != nil {
l.Error("update instance status error: %v", result.Error) l.Error("update instance status error: %v", result.Error)
middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError) middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError)
+3 -2
View File
@@ -41,8 +41,9 @@ type logStruct struct {
} }
type systemStruct struct { type systemStruct struct {
Salt string `yaml:"salt,omitempty"` Salt string `yaml:"salt,omitempty"`
Verify bool `yaml:"verify,omitempty"` Verify bool `yaml:"verify,omitempty"`
MountDir string `yaml:"mount_dir,omitempty"`
} }
var config = configStruct{ var config = configStruct{
+4
View File
@@ -53,6 +53,10 @@ func GetSystemVerify() bool {
return config.GetSystemVerify() return config.GetSystemVerify()
} }
func GetSystemMountDir() string {
return config.GetSystemMountDir()
}
func Save() error { func Save() error {
return config.Save() return config.Save()
} }
+4
View File
@@ -40,6 +40,10 @@ func (c *configStruct) GetSystemVerify() bool {
return c.System.Verify return c.System.Verify
} }
func (c *configStruct) GetSystemMountDir() string {
return c.System.MountDir
}
func (c *configStruct) Save() error { func (c *configStruct) Save() error {
return c.save() return c.save()
} }
+1
View File
@@ -37,6 +37,7 @@ func add(serverID uint, data Data) (err error) {
ctx := context.Background() ctx := context.Background()
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(serverID)), int64(instance.GpuCount)) 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)) 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.InstanceActionCreate)
return return
} }
+15 -8
View File
@@ -37,35 +37,37 @@ func control(serverID uint, data Data) (err error) {
return errors.New("instance status error") return errors.New("instance status error")
} }
if data.Action == instanceController.ActionPause && data.Status != models.InstanceRunning { if data.Action == instanceController.ActionPause && data.Status != models.InstanceStatusRunning {
lc.Error("instance status error") lc.Error("instance status error")
return errors.New("instance status error") return errors.New("instance status error")
} }
if data.Action == instanceController.ActionStart && data.Status != models.InstanceStopped && data.Status != models.InstancePaused { if data.Action == instanceController.ActionStart && data.Status != models.InstanceStatusStopped && data.Status != models.InstanceStatusPaused {
lc.Error("instance status error") lc.Error("instance status error")
return errors.New("instance status error") return errors.New("instance status error")
} }
switch data.Action { switch data.Action {
case instanceController.ActionStart: case instanceController.ActionStart:
if data.Status == models.InstancePaused { if data.Status == models.InstanceStatusPaused {
err = instanceController.Continue(&instance) err = instanceController.Continue(&instance)
if err != nil { if err != nil {
database.DB.Model(&instance).Update("status", models.InstanceStatusFail).Update("from_action", models.InstanceActionStart)
lc.Error("instance continue error: %v", err) lc.Error("instance continue error: %v", err)
return return
} }
} else if data.Status == models.InstanceStopped { } else if data.Status == models.InstanceStatusStopped {
err = instanceController.Restart(&instance) err = instanceController.Restart(&instance)
if err != nil { if err != nil {
lc.Error("instance restart error: %v", err)
ctx := context.Background() ctx := context.Background()
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(serverID)), int64(instance.GpuCount)) redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(serverID)), int64(instance.GpuCount))
database.DB.Model(&instance).Update("status", models.InstanceStatusFail).Update("from_action", models.InstanceActionStart)
lc.Error("instance restart error: %v", err)
return return
} }
} }
if data.Status == models.InstanceStopped && instance.Status == models.InstanceRunning { if data.Status == models.InstanceStatusStopped && instance.Status == models.InstanceStatusRunning {
server.GpuUsed += instance.GpuCount server.GpuUsed += instance.GpuCount
result = database.DB.Save(&server) result = database.DB.Save(&server)
if result.Error != nil { if result.Error != nil {
@@ -79,6 +81,7 @@ func control(serverID uint, data Data) (err error) {
case instanceController.ActionPause: case instanceController.ActionPause:
err = instanceController.Pause(&instance) err = instanceController.Pause(&instance)
if err != nil { if err != nil {
database.DB.Model(&instance).Update("status", models.InstanceStatusFail).Update("from_action", models.InstanceActionPause)
lc.Error("instance pause error: %v", err) lc.Error("instance pause error: %v", err)
return return
} }
@@ -88,14 +91,16 @@ func control(serverID uint, data Data) (err error) {
case instanceController.ActionStop: case instanceController.ActionStop:
err = instanceController.Stop(&instance) err = instanceController.Stop(&instance)
if err != nil { if err != nil {
database.DB.Model(&instance).Update("status", models.InstanceStatusFail).Update("from_action", models.InstanceActionStop)
lc.Error("instance stop error: %v", err) lc.Error("instance stop error: %v", err)
return return
} }
if (data.Status == models.InstanceRunning || data.Status == models.InstancePaused) && instance.Status == models.InstanceStopped { if (data.Status == models.InstanceStatusRunning || data.Status == models.InstanceStatusPaused) && instance.Status == models.InstanceStatusStopped {
server.GpuUsed -= instance.GpuCount server.GpuUsed -= instance.GpuCount
result = database.DB.Save(&server) result = database.DB.Save(&server)
if result.Error != nil { if result.Error != nil {
database.DB.Model(&instance).Update("status", models.InstanceStatusFail)
lc.Error("save server error: %v", result.Error) lc.Error("save server error: %v", result.Error)
return result.Error return result.Error
} }
@@ -106,14 +111,16 @@ func control(serverID uint, data Data) (err error) {
case instanceController.ActionRestart: case instanceController.ActionRestart:
err = instanceController.Restart(&instance) err = instanceController.Restart(&instance)
if err != nil { if err != nil {
database.DB.Model(&instance).Update("status", models.InstanceStatusFail).Update("from_action", models.InstanceActionRestart)
lc.Error("instance restart error: %v", err) lc.Error("instance restart error: %v", err)
return return
} }
if data.Status == models.InstanceStopped && instance.Status == models.InstanceRunning { if data.Status == models.InstanceStatusStopped && instance.Status == models.InstanceStatusRunning {
server.GpuUsed += instance.GpuCount server.GpuUsed += instance.GpuCount
result = database.DB.Save(&server) result = database.DB.Save(&server)
if result.Error != nil { if result.Error != nil {
database.DB.Model(&instance).Update("status", models.InstanceStatusFail)
lc.Error("save server error: %v", result.Error) lc.Error("save server error: %v", result.Error)
return result.Error return result.Error
} }
+39 -17
View File
@@ -34,25 +34,47 @@ func delete(serverID uint, data Data) (err error) {
err = instanceController.Delete(&instance) err = instanceController.Delete(&instance)
if err != nil { if err != nil {
lc.Error("delete instance error: %v", err) lc.Error("delete instance error: %v", err)
ctx := context.Background() if !data.Force {
if data.Status == models.InstanceRunning || data.Status == models.InstancePaused { ctx := context.Background()
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(serverID)), int64(-instance.GpuCount)) 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)) }
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 return
} }
server.VolumeUsed -= instance.VolumeSize + 30
if data.Status == models.InstanceRunning || data.Status == models.InstancePaused {
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 return
} }
+1
View File
@@ -21,6 +21,7 @@ type Data struct {
VolumeSize *int `json:"volume_size,omitempty"` VolumeSize *int `json:"volume_size,omitempty"`
Action instanceController.Action `json:"action,omitempty"` Action instanceController.Action `json:"action,omitempty"`
Force bool `json:"force,omitempty"`
} }
type Type int type Type int
+4 -3
View File
@@ -38,7 +38,7 @@ func modify(serverID uint, data Data) (err error) {
return result.Error return result.Error
} }
if data.Status != models.InstanceStopped { if data.Status != models.InstanceStatusStopped {
lc.Error("instance status error") lc.Error("instance status error")
return errors.New("instance status error") return errors.New("instance status error")
} }
@@ -60,14 +60,15 @@ func modify(serverID uint, data Data) (err error) {
err = instanceController.Patch(&instance, gpuCount, volumeSize, data.CpuOnly) err = instanceController.Patch(&instance, gpuCount, volumeSize, data.CpuOnly)
if err != nil { if err != nil {
lc.Error("patch instance error: %v", err)
ctx := context.Background() ctx := context.Background()
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(serverID)), int64(gpuCount)) redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(serverID)), int64(gpuCount))
redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(serverID)), int64(volumeSize-oldVolumeSize)) redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(serverID)), int64(volumeSize-oldVolumeSize))
database.DB.Model(&instance).Update("status", models.InstanceStatusFail).Update("from_action", models.InstanceActionModify)
lc.Error("patch instance error: %v", err)
return return
} }
if data.Status == models.InstanceStopped { if data.Status == models.InstanceStatusStopped {
server.GpuUsed += instance.GpuCount server.GpuUsed += instance.GpuCount
} }
server.VolumeUsed += instance.VolumeSize - oldVolumeSize server.VolumeUsed += instance.VolumeSize - oldVolumeSize
+2 -2
View File
@@ -12,7 +12,7 @@ import (
func Continue(instance *models.Instances) (err error) { func Continue(instance *models.Instances) (err error) {
l.SetFunction("Start") l.SetFunction("Start")
instance.Status = models.InstanceStarting instance.Status = models.InstanceStatusStarting
result := database.DB.Save(&instance) result := database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
@@ -34,7 +34,7 @@ func Continue(instance *models.Instances) (err error) {
return err return err
} }
instance.Status = models.InstanceRunning instance.Status = models.InstanceStatusRunning
result = database.DB.Save(&instance) result = database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
@@ -6,6 +6,7 @@ import (
"errors" "errors"
"megrez/libs/crypto" "megrez/libs/crypto"
"megrez/libs/request" "megrez/libs/request"
"megrez/services/config"
"strconv" "strconv"
) )
@@ -47,6 +48,7 @@ func createInstance(ip string, port int, apikey string,
}, },
Env: []string{ Env: []string{
"NVIDIA_DRIVER_CAPABILITIES=video,compute,utility", "NVIDIA_DRIVER_CAPABILITIES=video,compute,utility",
"NVIDIA_VISIBLE_DEVICES=none",
}, },
} }
@@ -56,13 +58,16 @@ func createInstance(ip string, port int, apikey string,
Src: volumeName, Src: volumeName,
Dest: "/root/megrez-tmp", Dest: "/root/megrez-tmp",
}, },
{
Src: "/data/pub",
Dest: "/root/megrez-pub",
},
} }
} }
if config.GetSystemMountDir() != "" {
data.Binds = append(data.Binds, bindStruct{
Src: config.GetSystemMountDir(),
Dest: "/root/megrez-pub",
})
}
reqBytes, err := json.Marshal(data) reqBytes, err := json.Marshal(data)
if err != nil { if err != nil {
l.Error("marshal request data error: %v", err) l.Error("marshal request data error: %v", err)
+1 -1
View File
@@ -8,7 +8,7 @@ import (
func Delete(instance *models.Instances) (err error) { func Delete(instance *models.Instances) (err error) {
l.SetFunction("Delete") l.SetFunction("Delete")
instance.Status = models.InstanceDeleting instance.Status = models.InstanceStatusDeleting
result := database.DB.Save(&instance) result := database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
+4 -4
View File
@@ -34,7 +34,7 @@ type volumePatchStruct struct {
func Patch(instance *models.Instances, gpuCount, volumeSize int, cpuOnly bool) (err error) { func Patch(instance *models.Instances, gpuCount, volumeSize int, cpuOnly bool) (err error) {
l.SetFunction("Patch") l.SetFunction("Patch")
instance.Status = models.InstanceModifying instance.Status = models.InstanceStatusModifying
result := database.DB.Save(&instance) result := database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
@@ -42,7 +42,7 @@ func Patch(instance *models.Instances, gpuCount, volumeSize int, cpuOnly bool) (
} }
if gpuCount == instance.GpuCount && volumeSize == instance.VolumeSize && cpuOnly == instance.CpuOnly { if gpuCount == instance.GpuCount && volumeSize == instance.VolumeSize && cpuOnly == instance.CpuOnly {
instance.Status = models.InstanceStopped instance.Status = models.InstanceStatusStopped
result = database.DB.Save(&instance) result = database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
@@ -113,7 +113,7 @@ func Patch(instance *models.Instances, gpuCount, volumeSize int, cpuOnly bool) (
instance.CpuOnly = true instance.CpuOnly = true
instance.GpuCount = 0 instance.GpuCount = 0
instance.Status = models.InstanceRunning instance.Status = models.InstanceStatusRunning
result = database.DB.Save(&instance) result = database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
@@ -162,7 +162,7 @@ func Patch(instance *models.Instances, gpuCount, volumeSize int, cpuOnly bool) (
instance.CpuOnly = false instance.CpuOnly = false
instance.GpuCount = gpuCount instance.GpuCount = gpuCount
instance.Status = models.InstanceRunning instance.Status = models.InstanceStatusRunning
result = database.DB.Save(&instance) result = database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
+2 -2
View File
@@ -12,7 +12,7 @@ import (
func Pause(instance *models.Instances) (err error) { func Pause(instance *models.Instances) (err error) {
l.SetFunction("Pause") l.SetFunction("Pause")
instance.Status = models.InstancePausing instance.Status = models.InstanceStatusPausing
result := database.DB.Save(&instance) result := database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
@@ -34,7 +34,7 @@ func Pause(instance *models.Instances) (err error) {
return err return err
} }
instance.Status = models.InstancePaused instance.Status = models.InstanceStatusPaused
result = database.DB.Save(&instance) result = database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
+4 -4
View File
@@ -12,10 +12,10 @@ import (
func Restart(instance *models.Instances) (err error) { func Restart(instance *models.Instances) (err error) {
l.SetFunction("Restart") l.SetFunction("Restart")
if instance.Status == models.InstanceStopped || instance.Status == models.InstancePaused { if instance.Status == models.InstanceStatusStopped || instance.Status == models.InstanceStatusPaused {
instance.Status = models.InstanceStarting instance.Status = models.InstanceStatusStarting
} else { } else {
instance.Status = models.InstanceRestarting instance.Status = models.InstanceStatusRestarting
} }
result := database.DB.Save(&instance) result := database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
@@ -65,7 +65,7 @@ func Restart(instance *models.Instances) (err error) {
instance.GrafanaAddress = server.IP + ":" + portBindings["3000"] instance.GrafanaAddress = server.IP + ":" + portBindings["3000"]
instance.CodeServerAddress = server.IP + ":" + portBindings["8080"] instance.CodeServerAddress = server.IP + ":" + portBindings["8080"]
instance.Status = models.InstanceRunning instance.Status = models.InstanceStatusRunning
result = database.DB.Save(&instance) result = database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
+2 -2
View File
@@ -12,7 +12,7 @@ import (
func Stop(instance *models.Instances) (err error) { func Stop(instance *models.Instances) (err error) {
l.SetFunction("Stop") l.SetFunction("Stop")
instance.Status = models.InstanceStopping instance.Status = models.InstanceStatusStopping
result := database.DB.Save(&instance) result := database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)
@@ -34,7 +34,7 @@ func Stop(instance *models.Instances) (err error) {
return err return err
} }
instance.Status = models.InstanceStopped instance.Status = models.InstanceStatusStopped
result = database.DB.Save(&instance) result = database.DB.Save(&instance)
if result.Error != nil { if result.Error != nil {
l.Error("save instance error: %v", result.Error) l.Error("save instance error: %v", result.Error)