mirror of
https://github.com/XShengTech/MEGREZ.git
synced 2026-05-03 13:02:38 +00:00
[Init] 🎉 MEGREZ Community
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func listHandler(ctx iris.Context) {
|
||||
l.SetFunction("listHandler")
|
||||
|
||||
res := make(map[string]string)
|
||||
|
||||
system := models.System{
|
||||
Key: imagesKey,
|
||||
}
|
||||
result := database.DB.FirstOrCreate(&system)
|
||||
if result.Error != nil {
|
||||
l.Error("get system error: %v", result.Error)
|
||||
middleware.Result(ctx, res)
|
||||
return
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(system.Value), &res)
|
||||
if err != nil {
|
||||
l.Error("unmarshal system error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Result(ctx, res)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func modifyHandler(ctx iris.Context) {
|
||||
l.SetFunction("modifyHandler")
|
||||
|
||||
req := make(map[string]string)
|
||||
err := ctx.ReadJSON(&req)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
system := models.System{
|
||||
Key: imagesKey,
|
||||
}
|
||||
result := database.DB.FirstOrCreate(&system)
|
||||
if result.Error != nil {
|
||||
l.Error("get system config error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
valueBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
l.Error("marshal system error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
system.Value = string(valueBytes)
|
||||
result = database.DB.Save(&system)
|
||||
if result.Error != nil {
|
||||
l.Error("save system error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/logger"
|
||||
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
|
||||
_logger "megrez/libs/logger"
|
||||
)
|
||||
|
||||
const imagesKey = "images"
|
||||
|
||||
var l *_logger.LoggerStruct
|
||||
|
||||
func InitImages(party router.Party) {
|
||||
l = logger.Logger.Clone()
|
||||
l.SetModel("Http.API.V1.Admin.Images")
|
||||
|
||||
party.Get("/", listHandler)
|
||||
party.Post("/", middleware.SuperAdminCheck, modifyHandler)
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/libs/crypto"
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/dispatcher"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type addReqStruct struct {
|
||||
UserID uint `json:"user_id"`
|
||||
ServerID uint `json:"server_id"`
|
||||
|
||||
ImageName string `json:"image_name"`
|
||||
GpuCount int `json:"gpu_count"`
|
||||
VolumeSize int `json:"volume_size"`
|
||||
}
|
||||
|
||||
func addHandler(ctx iris.Context) {
|
||||
l.SetFunction("addHandler")
|
||||
|
||||
var req addReqStruct
|
||||
err := ctx.ReadJSON(&req)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.UserID == 0 || req.ServerID == 0 || req.ImageName == "" || req.GpuCount <= 0 || req.VolumeSize < 50 {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
}
|
||||
|
||||
user := models.Users{
|
||||
ID: req.UserID,
|
||||
}
|
||||
result := database.DB.First(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("query user error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminUserQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: req.ServerID,
|
||||
}
|
||||
result = database.DB.First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("query server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
remainGpu, err := redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(-req.GpuCount)).Result()
|
||||
if err != nil {
|
||||
l.Error("incrby gpu num error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
remainVolume, err := redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID)), int64(-req.VolumeSize-30)).Result()
|
||||
if err != nil {
|
||||
l.Error("incrby volume size error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if remainGpu < 0 || remainVolume < 0 {
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(req.GpuCount))
|
||||
redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID)), int64(req.VolumeSize+30))
|
||||
middleware.Error(ctx, middleware.CodeResourceInsufficient, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
instance := models.Instances{
|
||||
UserID: req.UserID,
|
||||
ServerID: req.ServerID,
|
||||
ImageName: req.ImageName,
|
||||
GpuCount: req.GpuCount,
|
||||
VolumeSize: req.VolumeSize,
|
||||
|
||||
SshPasswd: crypto.Hex(16),
|
||||
|
||||
Status: models.InstanceReady,
|
||||
}
|
||||
result = database.DB.Create(&instance)
|
||||
if result.Error != nil {
|
||||
l.Error("create instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInternalCreateError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
dispatcherData := dispatcher.Data{
|
||||
Type: dispatcher.Add,
|
||||
InstanceID: instance.ID,
|
||||
}
|
||||
dispatcher.Push(instance.ServerID, dispatcherData)
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/dispatcher"
|
||||
"megrez/services/instanceController"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type controlStruct struct {
|
||||
Action instanceController.Action `json:"action"` // 1: start, 2: pause , 3: stop, 4: restart
|
||||
}
|
||||
|
||||
func controlHandler(ctx iris.Context) {
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req controlStruct
|
||||
err = ctx.ReadJSON(&req)
|
||||
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("detail instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceDetailError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if models.InstanceIngStatusCheck(instance.Status) {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Action == instanceController.ActionStop && instance.Status != models.InstanceRunning && instance.Status != models.InstancePaused {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Action == instanceController.ActionPause && instance.Status != models.InstanceRunning {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Action == instanceController.ActionStart && instance.Status != models.InstanceStopped && instance.Status != models.InstancePaused {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: instance.ServerID,
|
||||
}
|
||||
result = database.DB.First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("query server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
status := instance.Status
|
||||
if status == models.InstanceStopped && (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()
|
||||
if err != nil {
|
||||
l.Error("incrby gpu num error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if remainGpu < 0 {
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(instance.GpuCount))
|
||||
middleware.Error(ctx, middleware.CodeResourceInsufficient, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch req.Action {
|
||||
case instanceController.ActionStart:
|
||||
result = database.DB.Model(&instance).Update("status", models.InstanceStarting)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceStartError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
case instanceController.ActionPause:
|
||||
result = database.DB.Model(&instance).Update("status", models.InstancePausing)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstancePauseError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
case instanceController.ActionStop:
|
||||
result = database.DB.Model(&instance).Update("status", models.InstanceStopping)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceStopError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(instance.GpuCount))
|
||||
|
||||
case instanceController.ActionRestart:
|
||||
result = database.DB.Model(&instance).Update("status", models.InstanceRestarting)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceRestartError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
dispatcherData := dispatcher.Data{
|
||||
Type: dispatcher.Control,
|
||||
InstanceID: instance.ID,
|
||||
Status: status,
|
||||
Action: req.Action,
|
||||
}
|
||||
dispatcher.Push(instance.ServerID, dispatcherData)
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
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 deleteHandler(ctx iris.Context) {
|
||||
l.SetFunction("deleteHandler")
|
||||
|
||||
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 models.InstanceIngStatusCheck(status) {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
result = database.DB.Model(&instance).Update("status", models.InstanceDeleting)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if status == models.InstanceRunning || status == models.InstancePaused {
|
||||
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))
|
||||
|
||||
// TODO: Price calculation
|
||||
|
||||
dispatcherData := dispatcher.Data{
|
||||
Type: dispatcher.Delete,
|
||||
Status: status,
|
||||
InstanceID: instance.ID,
|
||||
}
|
||||
dispatcher.Push(instance.ServerID, dispatcherData)
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func detailHandler(ctx iris.Context) {
|
||||
l.SetFunction("detailHandler")
|
||||
|
||||
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.Select("id", "user_id", "server_id", "cpu_only", "gpu_count", "volume_size", "ssh_address", "ssh_passwd", "tensor_board_address", "grafana_address", "status", "image_name", "created_at").First(&instance)
|
||||
if result.Error != nil {
|
||||
l.Error("detail instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceDetailError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: instance.ServerID,
|
||||
}
|
||||
result = database.DB.Select("name", "gpu_type", "gpu_num").First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("detail server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceDetailError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
redis.RawDB.Get(ctx, "remain_gpu:server:"+strconv.Itoa(int(instance.ServerID))).Scan(&server.GpuUsed)
|
||||
server.GpuUsed = server.GpuNum - server.GpuUsed
|
||||
|
||||
res := instanceStruct{
|
||||
Instances: instance,
|
||||
GpuType: server.GpuType,
|
||||
GpuNum: server.GpuNum,
|
||||
GpuUsed: server.GpuUsed,
|
||||
}
|
||||
|
||||
middleware.Result(ctx, res)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type labelReqStruct struct {
|
||||
Label string `json:"label"`
|
||||
}
|
||||
|
||||
func labelHandler(ctx iris.Context) {
|
||||
l.SetFunction("labelHandler")
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req labelReqStruct
|
||||
err = ctx.ReadJSON(&req)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
instance := models.Instances{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.Where(&instance).First(&instance)
|
||||
if result.Error != nil {
|
||||
l.Error("query instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
result = database.DB.Model(&instance).Update("label", req.Label)
|
||||
if result.Error != nil {
|
||||
l.Error("save instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceSaveError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func listHandler(ctx iris.Context) {
|
||||
l.SetFunction("listHandler")
|
||||
var err error
|
||||
|
||||
offset := 0
|
||||
limit := 20
|
||||
offsetStr := ctx.URLParam("offset")
|
||||
limitStr := ctx.URLParam("limit")
|
||||
|
||||
if offsetStr != "" {
|
||||
offset, err = strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
if limitStr != "" {
|
||||
limit, err = strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var total int64
|
||||
var instances []models.Instances
|
||||
totalResult := database.DB.Model(&models.Instances{}).Count(&total)
|
||||
if totalResult.Error != nil {
|
||||
l.Error("list instances error: %v", totalResult.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceListError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
result := database.DB.Limit(limit).Offset(offset).Select("id", "user_id", "server_id", "cpu_only", "gpu_count", "volume_size", "ssh_address", "ssh_passwd", "jupyter_address", "tensor_board_address", "grafana_address", "status", "image_name", "label", "created_at").Order("id").Find(&instances)
|
||||
if result.Error != nil {
|
||||
l.Error("list instances error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceListError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
res := make([]instanceStruct, len(instances))
|
||||
for i, instance := range instances {
|
||||
res[i] = instanceStruct{
|
||||
Instances: instance,
|
||||
}
|
||||
user := models.Users{
|
||||
ID: instance.UserID,
|
||||
}
|
||||
result := database.DB.Select("username").First(&user)
|
||||
if result.Error == nil {
|
||||
res[i].Username = user.Username
|
||||
} else {
|
||||
l.Error("query user %d error: %v", instance.UserID, result.Error)
|
||||
}
|
||||
server := models.Servers{
|
||||
ID: instance.ServerID,
|
||||
}
|
||||
result = database.DB.Select("name", "gpu_type", "gpu_num", "cpu_count_per_gpu", "memory_per_gpu").First(&server)
|
||||
if result.Error == nil {
|
||||
|
||||
redis.RawDB.Get(ctx, "remain_gpu:server:"+strconv.Itoa(int(instance.ServerID))).Scan(&server.GpuUsed)
|
||||
server.GpuUsed = server.GpuNum - server.GpuUsed
|
||||
|
||||
res[i].ServerName = server.Name
|
||||
res[i].GpuType = server.GpuType
|
||||
res[i].GpuNum = server.GpuNum
|
||||
res[i].GpuUsed = server.GpuUsed
|
||||
res[i].CpuCountPerGpu = server.CpuCountPerGpu
|
||||
res[i].MemoryPerGpu = server.MemoryPerGpu
|
||||
} else {
|
||||
l.Error("query server %d error: %v", instance.ServerID, result.Error)
|
||||
}
|
||||
}
|
||||
|
||||
middleware.ResultWithTotal(ctx, res, total)
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
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"
|
||||
)
|
||||
|
||||
type modifyReqStruct struct {
|
||||
CpuOnly bool `json:"cpu_only"`
|
||||
GpuCount *int `json:"gpu_count"`
|
||||
VolumeSize *int `json:"volume_size"`
|
||||
}
|
||||
|
||||
func modifyHandler(ctx iris.Context) {
|
||||
l.SetFunction("modifyHandler")
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req modifyReqStruct
|
||||
err = ctx.ReadJSON(&req)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.GpuCount != nil {
|
||||
if *req.GpuCount < 0 {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if req.VolumeSize != nil {
|
||||
if *req.VolumeSize < 50 {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
instance := models.Instances{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.First(&instance)
|
||||
if result.Error != nil {
|
||||
l.Error("query instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if instance.Status != models.InstanceStopped {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.CpuOnly == instance.CpuOnly && req.CpuOnly {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: instance.ServerID,
|
||||
}
|
||||
result = database.DB.First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("query server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if req.GpuCount != nil {
|
||||
remainGpu, err := redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(-*req.GpuCount)).Result()
|
||||
if err != nil {
|
||||
l.Error("incrby gpu num error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if remainGpu < 0 {
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(*req.GpuCount))
|
||||
middleware.Error(ctx, middleware.CodeResourceInsufficient, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.VolumeSize != nil {
|
||||
remainVolume, err := redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID)), int64(instance.VolumeSize-*req.VolumeSize)).Result()
|
||||
if err != nil {
|
||||
l.Error("incrby volume size error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if remainVolume < 0 {
|
||||
redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID)), int64(*req.VolumeSize-instance.VolumeSize))
|
||||
middleware.Error(ctx, middleware.CodeResourceInsufficient, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
status := instance.Status
|
||||
result = database.DB.Model(&instance).Update("status", models.InstanceModifying)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
dispatcherData := dispatcher.Data{
|
||||
Type: dispatcher.Modify,
|
||||
InstanceID: instance.ID,
|
||||
Status: status,
|
||||
|
||||
CpuOnly: req.CpuOnly,
|
||||
GpuCount: req.GpuCount,
|
||||
VolumeSize: req.VolumeSize,
|
||||
}
|
||||
dispatcher.Push(instance.ServerID, dispatcherData)
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/logger"
|
||||
|
||||
_logger "megrez/libs/logger"
|
||||
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
)
|
||||
|
||||
var l *_logger.LoggerStruct
|
||||
|
||||
type instanceStruct struct {
|
||||
models.Instances
|
||||
Username string `json:"username"`
|
||||
ServerName string `json:"server_name"`
|
||||
GpuType string `json:"gpu_type"`
|
||||
GpuNum int `json:"gpu_num"`
|
||||
GpuUsed int `json:"gpu_used"`
|
||||
CpuCountPerGpu int `json:"cpu_count_per_gpu"`
|
||||
MemoryPerGpu int `json:"memory_per_gpu"`
|
||||
}
|
||||
|
||||
func InitInstances(party router.Party) {
|
||||
l = logger.Logger.Clone()
|
||||
l.SetModel("Http.API.V1.Admin.Instance")
|
||||
|
||||
party.Get("/", listHandler)
|
||||
party.Get("/{id:uint}", detailHandler)
|
||||
party.Put("/{id:uint}", middleware.SuperAdminCheck, controlHandler)
|
||||
party.Post("/", middleware.SuperAdminCheck, addHandler)
|
||||
party.Post("/{id:uint}", middleware.SuperAdminCheck, modifyHandler)
|
||||
party.Post("/{id:uint}/label", middleware.SuperAdminCheck, labelHandler)
|
||||
party.Delete("/{id:uint}", middleware.SuperAdminCheck, deleteHandler)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"megrez/routers/api/v1/admin/images"
|
||||
instances "megrez/routers/api/v1/admin/instance"
|
||||
"megrez/routers/api/v1/admin/servers"
|
||||
"megrez/routers/api/v1/admin/users"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
)
|
||||
|
||||
func InitAdmin(party router.Party) {
|
||||
party.Use(middleware.Auth, middleware.AuthCheck, middleware.AdminCheck)
|
||||
|
||||
users.InitUser(party.Party("/users"))
|
||||
servers.InitServer(party.Party("/servers"))
|
||||
instances.InitInstances(party.Party("/instances"))
|
||||
images.InitImages(party.Party("/images"))
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func addHandler(ctx iris.Context) {
|
||||
l.SetFunction("addHandler")
|
||||
|
||||
var s serverStruct
|
||||
if err := ctx.ReadJSON(&s); err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if s.Name == "" || s.IP == "" || s.Port == 0 || s.Apikey == "" || s.GpuType == "" || s.GpuNum == 0 || s.GpuDirverVersion == "" || s.GpuCudaVersion == "" || s.CpuCpuntPerGpu == 0 || s.MemoryPerGpu == 0 || s.VolumeTotal == 0 {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
l.Debug("add server: %+v", s)
|
||||
|
||||
server := models.Servers{
|
||||
Name: s.Name,
|
||||
IP: s.IP,
|
||||
Port: s.Port,
|
||||
Apikey: s.Apikey,
|
||||
GpuType: s.GpuType,
|
||||
GpuNum: s.GpuNum,
|
||||
GpuDriverVersion: s.GpuDirverVersion,
|
||||
GpuCudaVersion: s.GpuCudaVersion,
|
||||
|
||||
CpuCountPerGpu: s.CpuCpuntPerGpu,
|
||||
MemoryPerGpu: s.MemoryPerGpu,
|
||||
VolumeTotal: s.VolumeTotal,
|
||||
Price: s.Price,
|
||||
PriceVolume: s.PriceVolume,
|
||||
}
|
||||
result := database.DB.Create(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("add server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerAddEditError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(server.GpuNum))
|
||||
redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID)), int64(server.VolumeTotal))
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func deleteHandler(ctx iris.Context) {
|
||||
l.SetFunction("deleteHandler")
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var instances []models.Instances
|
||||
result := database.DB.Where("server_id = ?", id).Find(&instances)
|
||||
if result.Error != nil {
|
||||
l.Error("get instances error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerDeleteError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if len(instances) > 0 {
|
||||
middleware.Error(ctx, middleware.CodeAdminServerInstanceError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: id,
|
||||
}
|
||||
result = database.DB.Delete(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("delete server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerDeleteError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func detailHandler(ctx iris.Context) {
|
||||
l.SetFunction("detailHandler")
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("detail server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerDetailError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
redis.RawDB.Get(ctx, "remain_gpu:server:"+strconv.Itoa(int(id))).Scan(&server.GpuUsed)
|
||||
server.GpuUsed = server.GpuNum - server.GpuUsed
|
||||
|
||||
redis.RawDB.Get(ctx, "remain_volume:server:"+strconv.Itoa(int(id))).Scan(&server.VolumeUsed)
|
||||
server.VolumeUsed = server.VolumeTotal - server.VolumeUsed
|
||||
|
||||
middleware.Result(ctx, server)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func listHandler(ctx iris.Context) {
|
||||
l.SetFunction("listHandler")
|
||||
var err error
|
||||
|
||||
offset := 0
|
||||
limit := 20
|
||||
offsetStr := ctx.URLParam("offset")
|
||||
limitStr := ctx.URLParam("limit")
|
||||
|
||||
if offsetStr != "" {
|
||||
offset, err = strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
if limitStr != "" {
|
||||
limit, err = strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var total int64
|
||||
var servers []models.Servers
|
||||
totalResult := database.DB.Model(&models.Servers{}).Count(&total)
|
||||
if totalResult.Error != nil {
|
||||
l.Error("list servers error: %v", totalResult.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerListError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
result := database.DB.Limit(limit).Offset(offset).Select("id", "name", "ip", "gpu_type", "gpu_num", "gpu_driver_version", "gpu_cuda_version", "cpu_count_per_gpu", "memory_per_gpu", "volume_total", "price", "price_volume", "gpu_used", "volume_used", "created_at").Order("id").Find(&servers)
|
||||
if result.Error != nil {
|
||||
l.Error("list servers error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerListError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
for i, server := range servers {
|
||||
redis.RawDB.Get(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID))).Scan(&servers[i].GpuUsed)
|
||||
servers[i].GpuUsed = server.GpuNum - servers[i].GpuUsed
|
||||
|
||||
redis.RawDB.Get(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID))).Scan(&servers[i].VolumeUsed)
|
||||
servers[i].VolumeUsed = server.VolumeTotal - servers[i].VolumeUsed
|
||||
}
|
||||
|
||||
middleware.ResultWithTotal(ctx, servers, total)
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func modifyHandler(ctx iris.Context) {
|
||||
l.SetFunction("modifyHandler")
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req serverStruct
|
||||
if err := ctx.ReadJSON(&req); err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("query server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerAddEditError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name != "" && req.Name != server.Name {
|
||||
server.Name = req.Name
|
||||
}
|
||||
if req.IP != "" && req.IP != server.IP {
|
||||
server.IP = req.IP
|
||||
}
|
||||
if req.Port != 0 && req.Port != server.Port {
|
||||
server.Port = req.Port
|
||||
}
|
||||
if req.Apikey != "" && req.Apikey != server.Apikey {
|
||||
server.Apikey = req.Apikey
|
||||
}
|
||||
if req.GpuType != "" && req.GpuType != server.GpuType {
|
||||
server.GpuType = req.GpuType
|
||||
}
|
||||
if req.GpuNum != 0 && req.GpuNum != server.GpuNum {
|
||||
server.GpuNum = req.GpuNum
|
||||
}
|
||||
if req.GpuDirverVersion != "" && req.GpuDirverVersion != server.GpuDriverVersion {
|
||||
server.GpuDriverVersion = req.GpuDirverVersion
|
||||
}
|
||||
if req.GpuCudaVersion != "" && req.GpuCudaVersion != server.GpuCudaVersion {
|
||||
server.GpuCudaVersion = req.GpuCudaVersion
|
||||
}
|
||||
if req.CpuCpuntPerGpu != 0 && req.CpuCpuntPerGpu != server.CpuCountPerGpu {
|
||||
server.CpuCountPerGpu = req.CpuCpuntPerGpu
|
||||
}
|
||||
if req.MemoryPerGpu != 0 && req.MemoryPerGpu != server.MemoryPerGpu {
|
||||
server.MemoryPerGpu = req.MemoryPerGpu
|
||||
}
|
||||
if req.VolumeTotal != 0 && req.VolumeTotal != server.VolumeTotal {
|
||||
server.VolumeTotal = req.VolumeTotal
|
||||
}
|
||||
if req.Price != 0 && req.Price != server.Price {
|
||||
server.Price = req.Price
|
||||
}
|
||||
if req.PriceVolume != 0 && req.PriceVolume != server.PriceVolume {
|
||||
server.PriceVolume = req.PriceVolume
|
||||
}
|
||||
|
||||
result = database.DB.Save(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("save server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerAddEditError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/logger"
|
||||
|
||||
_logger "megrez/libs/logger"
|
||||
)
|
||||
|
||||
var l *_logger.LoggerStruct
|
||||
|
||||
type serverStruct struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
Port int `json:"port,omitempty"`
|
||||
Apikey string `json:"apikey,omitempty"`
|
||||
GpuType string `json:"gpu_type,omitempty"`
|
||||
GpuNum int `json:"gpu_num,omitempty"`
|
||||
GpuDirverVersion string `json:"gpu_driver_version,omitempty"`
|
||||
GpuCudaVersion string `json:"gpu_cuda_version,omitempty"`
|
||||
|
||||
CpuCpuntPerGpu int `json:"cpu_count_per_gpu,omitempty"`
|
||||
MemoryPerGpu int `json:"memory_per_gpu,omitempty"` // Unit `GB`
|
||||
VolumeTotal int `json:"volume_total,omitempty"` // Unit `GB`
|
||||
Price float64 `json:"price,omitempty"` // 1 GPU Per Hour
|
||||
PriceVolume float64 `json:"price_volume,omitempty"` // 1GB Per Hour
|
||||
}
|
||||
|
||||
func InitServer(party router.Party) {
|
||||
l = logger.Logger.Clone()
|
||||
l.SetModel("Http.API.V1.Admin.Servers")
|
||||
|
||||
party.Get("/", listHandler)
|
||||
party.Get("/{id:uint}", detailHandler)
|
||||
party.Post("/", middleware.SuperAdminCheck, addHandler)
|
||||
party.Post("/{id:uint}", middleware.SuperAdminCheck, modifyHandler)
|
||||
party.Delete("/{id:uint}", middleware.SuperAdminCheck, deleteHandler)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package users
|
||||
@@ -0,0 +1,49 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func deleteHandler(ctx iris.Context) {
|
||||
l.SetFunction("deleteHandler")
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if id == 1 {
|
||||
middleware.Error(ctx, middleware.CodeAdminUserDeleteError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var instances []models.Instances
|
||||
result := database.DB.Where("user_id = ?", id).Find(&instances)
|
||||
if result.Error != nil {
|
||||
l.Error("get user instances error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminUserDeleteError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if len(instances) > 0 {
|
||||
middleware.Error(ctx, middleware.CodeAdminUserInstanceNoEmpty, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user := models.Users{
|
||||
ID: id,
|
||||
}
|
||||
result = database.DB.Delete(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("delete user error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminUserDeleteError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func detailHandler(ctx iris.Context) {
|
||||
l.SetFunction("detailHandler")
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user := models.Users{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.Select("id", "username", "email", "role", "balance", "created_at").First(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("detail user error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminUserDetailError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Result(ctx, user)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func listHandler(ctx iris.Context) {
|
||||
l.SetFunction("listHandler")
|
||||
var err error
|
||||
|
||||
offset := 0
|
||||
limit := 20
|
||||
offsetStr := ctx.URLParam("offset")
|
||||
limitStr := ctx.URLParam("limit")
|
||||
|
||||
if offsetStr != "" {
|
||||
offset, err = strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
if limitStr != "" {
|
||||
limit, err = strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var total int64
|
||||
var users []models.Users
|
||||
totalResult := database.DB.Model(&models.Users{}).Count(&total)
|
||||
if totalResult.Error != nil {
|
||||
l.Error("list users error: %v", totalResult.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminUserListError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
result := database.DB.Limit(limit).Offset(offset).Select("id", "username", "email", "role", "balance", "created_at").Order("id").Find(&users)
|
||||
if result.Error != nil {
|
||||
l.Error("list users error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminUserListError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.ResultWithTotal(ctx, users, total)
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type modifyReqStruct struct {
|
||||
Password *string `json:"password"`
|
||||
Role *int `json:"role"`
|
||||
}
|
||||
|
||||
func modifyHandler(ctx iris.Context) {
|
||||
l.SetFunction("modifyHandler")
|
||||
|
||||
userId, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req modifyReqStruct
|
||||
err = ctx.ReadJSON(&req)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if userId == 1 {
|
||||
if req.Role != nil {
|
||||
middleware.Error(ctx, middleware.CodeAdminUserModifyError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
user := models.Users{
|
||||
ID: userId,
|
||||
}
|
||||
result := database.DB.Where(&user).First(&user)
|
||||
if result.Error != nil {
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Password != nil {
|
||||
if *req.Password != "" {
|
||||
user.Password = user.PasswordHash(*req.Password)
|
||||
}
|
||||
}
|
||||
|
||||
if req.Role != nil {
|
||||
user.Role = *req.Role
|
||||
}
|
||||
|
||||
result = database.DB.Save(&user)
|
||||
if result.Error != nil {
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
_logger "megrez/libs/logger"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/logger"
|
||||
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
)
|
||||
|
||||
var l *_logger.LoggerStruct
|
||||
|
||||
func InitUser(party router.Party) {
|
||||
l = logger.Logger.Clone()
|
||||
l.SetModel("Http.API.V1.Admin.Users")
|
||||
|
||||
party.Get("/", listHandler)
|
||||
party.Get("/{id:uint}", detailHandler)
|
||||
// party.Post("/", addHandler)
|
||||
party.Post("/{id:uint}", middleware.SuperAdminCheck, modifyHandler)
|
||||
party.Delete("/{id:uint}", middleware.SuperAdminCheck, deleteHandler)
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package middleware
|
||||
|
||||
type ResCode int
|
||||
|
||||
const (
|
||||
CodeSuccess ResCode = 200
|
||||
CodeServeBusy ResCode = 500
|
||||
CodeBadRequest ResCode = 400
|
||||
CodeUnauthorized ResCode = 401
|
||||
CodeForbidden ResCode = 403
|
||||
|
||||
CodePasswordError ResCode = 1000
|
||||
CodeLoginError ResCode = 1001
|
||||
CodeUserNotExist ResCode = 1002
|
||||
CodeRegisterRequestError ResCode = 1003
|
||||
CodeRegisterError ResCode = 1004
|
||||
CodeInternalCreateError ResCode = 1010
|
||||
CodeInstanceDeleteError ResCode = 1011
|
||||
CodeInstanceQueryError ResCode = 1012
|
||||
CodeInternalPatchError ResCode = 1013
|
||||
CodeInstanceListError ResCode = 1014
|
||||
CodeInstanceDetailError ResCode = 1015
|
||||
CodeInstanceStartError ResCode = 1016
|
||||
CodeInstancePauseError ResCode = 1017
|
||||
CodeInstanceStopError ResCode = 1018
|
||||
CodeInstanceRestartError ResCode = 1019
|
||||
CodeInstanceStatusError ResCode = 1020
|
||||
CodeInstanceSaveError ResCode = 1021
|
||||
|
||||
CodeServerQueryError ResCode = 1031
|
||||
CodeServerSaveError ResCode = 1032
|
||||
CodeResourceInsufficient ResCode = 1040
|
||||
|
||||
CodeAdminServerAddEditError ResCode = 2001
|
||||
CodeAdminServerListError ResCode = 2002
|
||||
CodeAdminServerDetailError ResCode = 2003
|
||||
CodeAdminServerDeleteError ResCode = 2004
|
||||
CodeAdminServerInstanceError ResCode = 2005
|
||||
CodeAdminUserQueryError ResCode = 2010
|
||||
CodeAdminUserListError ResCode = 2011
|
||||
CodeAdminUserDetailError ResCode = 2012
|
||||
CodeAdminUserDeleteError ResCode = 2013
|
||||
CodeAdminUserInstanceNoEmpty ResCode = 2014
|
||||
CodeAdminUserModifyError ResCode = 2015
|
||||
)
|
||||
|
||||
var codeMsgMap = map[ResCode]string{
|
||||
CodeSuccess: "success",
|
||||
CodeServeBusy: "server busy",
|
||||
CodeUnauthorized: "unauthorized",
|
||||
CodeBadRequest: "bad request",
|
||||
CodeForbidden: "forbidden",
|
||||
|
||||
CodePasswordError: "password error",
|
||||
CodeLoginError: "login error",
|
||||
CodeUserNotExist: "user not exist",
|
||||
CodeRegisterRequestError: "register request error",
|
||||
CodeRegisterError: "username or email exist",
|
||||
CodeInternalCreateError: "create error",
|
||||
CodeInstanceDeleteError: "delete instance error",
|
||||
CodeInstanceStatusError: "instance status error",
|
||||
CodeInstanceQueryError: "query instance error",
|
||||
CodeInstanceListError: "list instance error",
|
||||
CodeInstanceDetailError: "detail instance error",
|
||||
CodeInstanceStartError: "start instance error",
|
||||
CodeInstancePauseError: "pause instance error",
|
||||
CodeInstanceStopError: "stop instance error",
|
||||
CodeInstanceRestartError: "restart instance error",
|
||||
CodeResourceInsufficient: "resource insufficient",
|
||||
CodeInternalPatchError: "patch error",
|
||||
CodeInstanceSaveError: "save instance error",
|
||||
|
||||
CodeServerQueryError: "query server error",
|
||||
CodeServerSaveError: "save server error",
|
||||
|
||||
CodeAdminServerAddEditError: "add server error",
|
||||
CodeAdminServerListError: "list server error",
|
||||
CodeAdminServerDetailError: "detail server error",
|
||||
CodeAdminServerDeleteError: "delete server error",
|
||||
CodeAdminServerInstanceError: "server instances not empty",
|
||||
CodeAdminUserQueryError: "query user error",
|
||||
CodeAdminUserListError: "list user error",
|
||||
CodeAdminUserDetailError: "detail user error",
|
||||
CodeAdminUserDeleteError: "delete user error",
|
||||
CodeAdminUserModifyError: "modify user error",
|
||||
CodeAdminUserInstanceNoEmpty: "user instances not empty",
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"megrez/routers/api/v1/sessions"
|
||||
"megrez/services/redis"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func Auth(ctx iris.Context) {
|
||||
sess := sessions.Session()
|
||||
sess.UseDatabase(redis.DB)
|
||||
session := sess.Start(ctx)
|
||||
|
||||
auth, _ := session.GetBoolean("authenticated")
|
||||
if !auth {
|
||||
ctx.Values().Set("authenticated", false)
|
||||
ctx.Next()
|
||||
return
|
||||
} else {
|
||||
ctx.Values().Set("authenticated", true)
|
||||
}
|
||||
|
||||
userId, _ := session.GetInt("userId")
|
||||
ctx.Values().Set("userId", userId)
|
||||
ctx.Values().Set("email", session.GetString("email"))
|
||||
|
||||
role, _ := session.GetInt("role")
|
||||
ctx.Values().Set("role", role)
|
||||
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
func AuthCheck(ctx iris.Context) {
|
||||
if ctx.Values().Get("authenticated") == nil || !ctx.Values().Get("authenticated").(bool) {
|
||||
Error(ctx, CodeUnauthorized, iris.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
func UserCheck(ctx iris.Context) {
|
||||
usertype, _ := ctx.Values().GetInt("role")
|
||||
if usertype < 1 {
|
||||
Error(ctx, CodeForbidden, iris.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
func AdminCheck(ctx iris.Context) {
|
||||
usertype, _ := ctx.Values().GetInt("role")
|
||||
if usertype < 2 {
|
||||
Error(ctx, CodeForbidden, iris.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
func SuperAdminCheck(ctx iris.Context) {
|
||||
usertype, _ := ctx.Values().GetInt("role")
|
||||
if usertype < 3 {
|
||||
Error(ctx, CodeForbidden, iris.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Next()
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package middleware
|
||||
|
||||
import "github.com/kataras/iris/v12"
|
||||
|
||||
func Success(ctx iris.Context) {
|
||||
ctx.JSON(Response{
|
||||
Code: CodeSuccess,
|
||||
Msg: codeMsgMap[CodeSuccess],
|
||||
Data: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func Result(ctx iris.Context, data any) {
|
||||
ctx.JSON(Response{
|
||||
Code: CodeSuccess,
|
||||
Msg: codeMsgMap[CodeSuccess],
|
||||
Data: &Data{
|
||||
Result: data,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func ResultWithTotal(ctx iris.Context, data any, total int64) {
|
||||
ctx.JSON(Response{
|
||||
Code: CodeSuccess,
|
||||
Msg: codeMsgMap[CodeSuccess],
|
||||
Data: &Data{
|
||||
Result: data,
|
||||
Total: total,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func Error(ctx iris.Context, code ResCode, statusCode int) {
|
||||
ctx.StatusCode(statusCode)
|
||||
ctx.JSON(Response{
|
||||
Code: code,
|
||||
Msg: codeMsgMap[code],
|
||||
Data: nil,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package middleware
|
||||
|
||||
type Response struct {
|
||||
Code ResCode `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data *Data `json:"data"`
|
||||
}
|
||||
|
||||
type Data struct {
|
||||
Result any `json:"result"`
|
||||
Total int64 `json:"total,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"megrez/routers/api/v1/admin"
|
||||
"megrez/routers/api/v1/user"
|
||||
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
)
|
||||
|
||||
func InitApiV1(party router.Party) {
|
||||
admin.InitAdmin(party.Party("/admin"))
|
||||
user.InitUser(party.Party("/user"))
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package sessions
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12/sessions"
|
||||
)
|
||||
|
||||
func Session() *sessions.Sessions {
|
||||
return sessions.New(sessions.Config{
|
||||
Cookie: "session_id",
|
||||
Expires: 7 * 24 * time.Hour, // 7 Days
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func listHandler(ctx iris.Context) {
|
||||
l.SetFunction("listHandler")
|
||||
|
||||
res := make(map[string]string)
|
||||
|
||||
system := models.System{
|
||||
Key: imagesKey,
|
||||
}
|
||||
result := database.DB.First(&system)
|
||||
if result.Error != nil {
|
||||
l.Error("get system error: %v", result.Error)
|
||||
middleware.Result(ctx, res)
|
||||
return
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(system.Value), &res)
|
||||
if err != nil {
|
||||
l.Error("unmarshal system error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServeBusy, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Result(ctx, res)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package images
|
||||
|
||||
import (
|
||||
"megrez/services/logger"
|
||||
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
|
||||
_logger "megrez/libs/logger"
|
||||
)
|
||||
|
||||
const imagesKey = "images"
|
||||
|
||||
var l *_logger.LoggerStruct
|
||||
|
||||
func InitImages(party router.Party) {
|
||||
l = logger.Logger.Clone()
|
||||
l.SetModel("Http.API.V1.User.Images")
|
||||
|
||||
party.Get("/", listHandler)
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/libs/crypto"
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/dispatcher"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type addReqStruct struct {
|
||||
ServerID uint `json:"server_id"`
|
||||
|
||||
ImageName string `json:"image_name"`
|
||||
GpuCount int `json:"gpu_count"`
|
||||
VolumeSize int `json:"volume_size"`
|
||||
}
|
||||
|
||||
func addHandler(ctx iris.Context) {
|
||||
l.SetFunction("addHandler")
|
||||
|
||||
userId, err := ctx.Values().GetInt("userId")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req addReqStruct
|
||||
err = ctx.ReadJSON(&req)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.ServerID == 0 || req.ImageName == "" || req.GpuCount <= 0 || req.VolumeSize < 50 {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: req.ServerID,
|
||||
}
|
||||
result := database.DB.First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("query server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
remainGpu, err := redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(-req.GpuCount)).Result()
|
||||
if err != nil {
|
||||
l.Error("incrby gpu num error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
remainVolume, err := redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID)), int64(-req.VolumeSize-30)).Result()
|
||||
if err != nil {
|
||||
l.Error("incrby volume size error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if remainGpu < 0 || remainVolume < 0 {
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(req.GpuCount))
|
||||
redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID)), int64(req.VolumeSize+30))
|
||||
middleware.Error(ctx, middleware.CodeResourceInsufficient, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
instance := models.Instances{
|
||||
UserID: uint(userId),
|
||||
ServerID: req.ServerID,
|
||||
ImageName: req.ImageName,
|
||||
GpuCount: req.GpuCount,
|
||||
VolumeSize: req.VolumeSize,
|
||||
|
||||
SshPasswd: crypto.Hex(16),
|
||||
|
||||
Status: models.InstanceReady,
|
||||
}
|
||||
result = database.DB.Create(&instance)
|
||||
if result.Error != nil {
|
||||
l.Error("create instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInternalCreateError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
dispatcherData := dispatcher.Data{
|
||||
Type: dispatcher.Add,
|
||||
InstanceID: instance.ID,
|
||||
}
|
||||
dispatcher.Push(instance.ServerID, dispatcherData)
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/dispatcher"
|
||||
"megrez/services/instanceController"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type controlStruct struct {
|
||||
Action instanceController.Action `json:"action"` // 1: start, 2: pause , 3: stop, 4: restart
|
||||
}
|
||||
|
||||
func controlHandler(ctx iris.Context) {
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
userId, err := ctx.Values().GetInt("userId")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req controlStruct
|
||||
err = ctx.ReadJSON(&req)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
instance := models.Instances{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.Where("id = ?", id).Where("user_id = ?", userId).First(&instance)
|
||||
if result.Error != nil {
|
||||
l.Error("detail instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceDetailError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if models.InstanceIngStatusCheck(instance.Status) {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Action == instanceController.ActionStop && instance.Status != models.InstanceRunning && instance.Status != models.InstancePaused {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Action == instanceController.ActionPause && instance.Status != models.InstanceRunning {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Action == instanceController.ActionStart && instance.Status != models.InstanceStopped && instance.Status != models.InstancePaused {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: instance.ServerID,
|
||||
}
|
||||
result = database.DB.First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("query server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
status := instance.Status
|
||||
if status == models.InstanceStopped && (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()
|
||||
if err != nil {
|
||||
l.Error("incrby gpu num error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if remainGpu < 0 {
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(instance.GpuCount))
|
||||
middleware.Error(ctx, middleware.CodeResourceInsufficient, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch req.Action {
|
||||
case instanceController.ActionStart:
|
||||
result = database.DB.Model(&instance).Update("status", models.InstanceStarting)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceStartError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
case instanceController.ActionPause:
|
||||
result = database.DB.Model(&instance).Update("status", models.InstancePausing)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstancePauseError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
case instanceController.ActionStop:
|
||||
result = database.DB.Model(&instance).Update("status", models.InstanceStopping)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceStopError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(instance.GpuCount))
|
||||
|
||||
case instanceController.ActionRestart:
|
||||
result = database.DB.Model(&instance).Update("status", models.InstanceRestarting)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceRestartError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
dispatcherData := dispatcher.Data{
|
||||
Type: dispatcher.Control,
|
||||
InstanceID: instance.ID,
|
||||
Status: status,
|
||||
Action: req.Action,
|
||||
}
|
||||
dispatcher.Push(instance.ServerID, dispatcherData)
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
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 deleteHandler(ctx iris.Context) {
|
||||
l.SetFunction("deleteHandler")
|
||||
|
||||
userId, err := ctx.Values().GetInt("userId")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var instance models.Instances
|
||||
result := database.DB.Where("id = ?", id).Where("user_id = ?", userId).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 models.InstanceIngStatusCheck(status) {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
result = database.DB.Model(&instance).Update("status", models.InstanceDeleting)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if status == models.InstanceRunning || status == models.InstancePaused {
|
||||
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))
|
||||
|
||||
// TODO: Price calculation
|
||||
|
||||
dispatcherData := dispatcher.Data{
|
||||
Type: dispatcher.Delete,
|
||||
Status: status,
|
||||
InstanceID: instance.ID,
|
||||
}
|
||||
dispatcher.Push(instance.ServerID, dispatcherData)
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func detailHandler(ctx iris.Context) {
|
||||
l.SetFunction("detailHandler")
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
userId, err := ctx.Values().GetInt("userId")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
instance := models.Instances{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.Where("id = ?", id).Where("user_id = ?", userId).Select("id", "server_id", "cpu_only", "gpu_count", "volume_size", "ssh_address", "ssh_passwd", "tensor_board_address", "grafana_address", "status", "image_name", "created_at").First(&instance)
|
||||
if result.Error != nil {
|
||||
l.Error("detail instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceDetailError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: instance.ServerID,
|
||||
}
|
||||
result = database.DB.Select("name", "gpu_type", "gpu_num", "cpu_count_per_gpu", "memory_per_gpu").First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("detail server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceDetailError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
redis.RawDB.Get(ctx, "remain_gpu:server:"+strconv.Itoa(int(instance.ServerID))).Scan(&server.GpuUsed)
|
||||
server.GpuUsed = server.GpuNum - server.GpuUsed
|
||||
|
||||
res := instanceStruct{
|
||||
Instances: instance,
|
||||
GpuType: server.GpuType,
|
||||
GpuNum: server.GpuNum,
|
||||
GpuUsed: server.GpuUsed,
|
||||
CpuCountPerGpu: server.CpuCountPerGpu,
|
||||
MemoryPerGpu: server.MemoryPerGpu,
|
||||
}
|
||||
|
||||
middleware.Result(ctx, res)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type labelReqStruct struct {
|
||||
Label string `json:"label"`
|
||||
}
|
||||
|
||||
func labelHandler(ctx iris.Context) {
|
||||
l.SetFunction("labelHandler")
|
||||
|
||||
userId, err := ctx.Values().GetInt("userId")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req labelReqStruct
|
||||
err = ctx.ReadJSON(&req)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
instance := models.Instances{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.Where(&instance).Where("user_id = ?", userId).First(&instance)
|
||||
if result.Error != nil {
|
||||
l.Error("query instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
result = database.DB.Model(&instance).Update("label", req.Label)
|
||||
if result.Error != nil {
|
||||
l.Error("save instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceSaveError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func listHandler(ctx iris.Context) {
|
||||
l.SetFunction("listHandler")
|
||||
var err error
|
||||
|
||||
userId, err := ctx.Values().GetInt("userId")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
offset := 0
|
||||
limit := 20
|
||||
offsetStr := ctx.URLParam("offset")
|
||||
limitStr := ctx.URLParam("limit")
|
||||
|
||||
if offsetStr != "" {
|
||||
offset, err = strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
if limitStr != "" {
|
||||
limit, err = strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var total int64
|
||||
var instances []models.Instances
|
||||
totalResult := database.DB.Model(&models.Instances{}).Where("user_id = ?", userId).Count(&total)
|
||||
if totalResult.Error != nil {
|
||||
l.Error("list instances error: %v", totalResult.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceListError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
result := database.DB.Where("user_id = ?", userId).Limit(limit).Offset(offset).Select("id", "server_id", "cpu_only", "gpu_count", "volume_size", "ssh_address", "ssh_passwd", "jupyter_address", "tensor_board_address", "grafana_address", "status", "image_name", "label", "created_at").Order("id").Find(&instances)
|
||||
if result.Error != nil {
|
||||
l.Error("list instances error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceListError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
res := make([]instanceStruct, len(instances))
|
||||
for i, instance := range instances {
|
||||
res[i] = instanceStruct{
|
||||
Instances: instance,
|
||||
}
|
||||
server := models.Servers{
|
||||
ID: instance.ServerID,
|
||||
}
|
||||
result := database.DB.Select("name", "gpu_type", "gpu_num", "cpu_count_per_gpu", "memory_per_gpu").First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("query server %d error: %v", instance.ServerID, result.Error)
|
||||
continue
|
||||
}
|
||||
|
||||
redis.RawDB.Get(ctx, "remain_gpu:server:"+strconv.Itoa(int(instance.ServerID))).Scan(&server.GpuUsed)
|
||||
server.GpuUsed = server.GpuNum - server.GpuUsed
|
||||
|
||||
res[i].ServerName = server.Name
|
||||
res[i].GpuType = server.GpuType
|
||||
res[i].GpuNum = server.GpuNum
|
||||
res[i].GpuUsed = server.GpuUsed
|
||||
res[i].CpuCountPerGpu = server.CpuCountPerGpu
|
||||
res[i].MemoryPerGpu = server.MemoryPerGpu
|
||||
}
|
||||
|
||||
middleware.ResultWithTotal(ctx, res, total)
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
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"
|
||||
)
|
||||
|
||||
type modifyReqStruct struct {
|
||||
CpuOnly bool `json:"cpu_only"`
|
||||
GpuCount *int `json:"gpu_count"`
|
||||
VolumeSize *int `json:"volume_size"`
|
||||
}
|
||||
|
||||
func modifyHandler(ctx iris.Context) {
|
||||
l.SetFunction("modifyHandler")
|
||||
|
||||
userId, err := ctx.Values().GetInt("userId")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req modifyReqStruct
|
||||
err = ctx.ReadJSON(&req)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.GpuCount != nil {
|
||||
if *req.GpuCount < 0 {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if req.VolumeSize != nil {
|
||||
if *req.VolumeSize < 50 {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
instance := models.Instances{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.Where(&instance).Where("user_id = ?", userId).First(&instance)
|
||||
if result.Error != nil {
|
||||
l.Error("query instance error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInstanceQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if instance.Status != models.InstanceStopped {
|
||||
middleware.Error(ctx, middleware.CodeInstanceStatusError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.CpuOnly == instance.CpuOnly && req.CpuOnly {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: instance.ServerID,
|
||||
}
|
||||
result = database.DB.First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("query server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if req.GpuCount != nil {
|
||||
remainGpu, err := redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(-*req.GpuCount)).Result()
|
||||
if err != nil {
|
||||
l.Error("incrby gpu num error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if remainGpu < 0 {
|
||||
redis.RawDB.IncrBy(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID)), int64(*req.GpuCount))
|
||||
middleware.Error(ctx, middleware.CodeResourceInsufficient, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.VolumeSize != nil {
|
||||
remainVolume, err := redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID)), int64(instance.VolumeSize-*req.VolumeSize)).Result()
|
||||
if err != nil {
|
||||
l.Error("incrby volume size error: %v", err)
|
||||
middleware.Error(ctx, middleware.CodeServerQueryError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if remainVolume < 0 {
|
||||
redis.RawDB.IncrBy(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID)), int64(*req.VolumeSize-instance.VolumeSize))
|
||||
middleware.Error(ctx, middleware.CodeResourceInsufficient, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
status := instance.Status
|
||||
result = database.DB.Model(&instance).Update("status", models.InstanceModifying)
|
||||
if result.Error != nil {
|
||||
l.Error("update instance status error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeServerSaveError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
dispatcherData := dispatcher.Data{
|
||||
Type: dispatcher.Modify,
|
||||
InstanceID: instance.ID,
|
||||
Status: status,
|
||||
|
||||
CpuOnly: req.CpuOnly,
|
||||
GpuCount: req.GpuCount,
|
||||
VolumeSize: req.VolumeSize,
|
||||
}
|
||||
dispatcher.Push(instance.ServerID, dispatcherData)
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package instances
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/logger"
|
||||
|
||||
_logger "megrez/libs/logger"
|
||||
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
)
|
||||
|
||||
var l *_logger.LoggerStruct
|
||||
|
||||
type instanceStruct struct {
|
||||
models.Instances
|
||||
ServerName string `json:"server_name"`
|
||||
GpuType string `json:"gpu_type"`
|
||||
GpuNum int `json:"gpu_num"`
|
||||
GpuUsed int `json:"gpu_used"`
|
||||
CpuCountPerGpu int `json:"cpu_count_per_gpu"`
|
||||
MemoryPerGpu int `json:"memory_per_gpu"`
|
||||
}
|
||||
|
||||
func InitInstances(party router.Party) {
|
||||
l = logger.Logger.Clone()
|
||||
l.SetModel("Http.API.V1.User.Instance")
|
||||
|
||||
party.Use(middleware.AuthCheck, middleware.UserCheck)
|
||||
|
||||
party.Get("/", listHandler)
|
||||
party.Get("/{id:uint}", detailHandler)
|
||||
party.Put("/{id:uint}", controlHandler)
|
||||
party.Post("/", addHandler)
|
||||
party.Post("/{id:uint}", modifyHandler)
|
||||
party.Post("/{id:uint}/label", labelHandler)
|
||||
party.Delete("/{id:uint}", deleteHandler)
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/routers/api/v1/sessions"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type userLoginStruct struct {
|
||||
Account string `json:"account"`
|
||||
Password string `json:"password"`
|
||||
// HCaptchaToken string
|
||||
// CaptchaType string
|
||||
// Key string
|
||||
}
|
||||
|
||||
func loginHandler(ctx iris.Context) {
|
||||
sess := sessions.Session()
|
||||
session := sess.Start(ctx)
|
||||
sess.UseDatabase(redis.DB)
|
||||
|
||||
var userReq userLoginStruct
|
||||
if err := ctx.ReadJSON(&userReq); err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if userReq.Account == "" || userReq.Password == "" {
|
||||
middleware.Error(ctx, middleware.CodeLoginError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user := models.Users{}
|
||||
result := database.DB.Where("username = ?", userReq.Account).Or("email = ?", userReq.Account).First(&user)
|
||||
if result.Error != nil {
|
||||
middleware.Error(ctx, middleware.CodeLoginError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if !user.CheckPassword(userReq.Password) {
|
||||
middleware.Error(ctx, middleware.CodeLoginError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if user.Role < 1 {
|
||||
middleware.Error(ctx, middleware.CodeForbidden, iris.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
session.Set("authenticated", true)
|
||||
session.Set("userId", user.ID)
|
||||
session.Set("username", user.Username)
|
||||
session.Set("email", user.Email)
|
||||
session.Set("role", user.Role)
|
||||
session.Set("loginTime", time.Now().Unix())
|
||||
|
||||
profile := profile{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Role: user.Role,
|
||||
Balance: user.Balance,
|
||||
}
|
||||
|
||||
middleware.Result(ctx, profile)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/routers/api/v1/sessions"
|
||||
"megrez/services/redis"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func logoutHandler(ctx iris.Context) {
|
||||
sess := sessions.Session()
|
||||
session := sess.Start(ctx)
|
||||
sess.UseDatabase(redis.DB)
|
||||
sessionId := session.ID()
|
||||
|
||||
session.Destroy()
|
||||
ctx.SetCookie(&http.Cookie{
|
||||
Name: "session_id",
|
||||
Value: sessionId,
|
||||
Expires: time.Now(),
|
||||
})
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package user
|
||||
@@ -0,0 +1,46 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type profile struct {
|
||||
ID uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Role int `json:"role"`
|
||||
Balance float64 `json:"balance"`
|
||||
}
|
||||
|
||||
func profileHandler(ctx iris.Context) {
|
||||
l.SetFunction("profileHandler")
|
||||
userId, err := ctx.Values().GetInt("userId")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user := models.Users{
|
||||
ID: uint(userId),
|
||||
}
|
||||
result := database.DB.First(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("get user error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeUserNotExist, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
profile := profile{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Role: user.Role,
|
||||
Balance: user.Balance,
|
||||
}
|
||||
|
||||
middleware.Result(ctx, profile)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/config"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type registerStruct struct {
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func registerHandler(ctx iris.Context) {
|
||||
l.SetFunction("registerHandler")
|
||||
|
||||
var userReq registerStruct
|
||||
if err := ctx.ReadJSON(&userReq); err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if userReq.Username == "" || userReq.Email == "" || userReq.Password == "" {
|
||||
middleware.Error(ctx, middleware.CodeRegisterRequestError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user := models.Users{
|
||||
Username: userReq.Username,
|
||||
Email: userReq.Email,
|
||||
Role: 0,
|
||||
Balance: 0,
|
||||
}
|
||||
user.Password = user.PasswordHash(userReq.Password)
|
||||
|
||||
if !config.GetSystemVerify() {
|
||||
user.Role = 1
|
||||
}
|
||||
|
||||
result := database.DB.Create(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("create user error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeRegisterError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
type resetPasswordStruct struct {
|
||||
OldPassword string `json:"old_password"`
|
||||
NewPassword string `json:"new_password"`
|
||||
}
|
||||
|
||||
func resetPasswordHandler(ctx iris.Context) {
|
||||
l.SetFunction("resetPasswordHandler")
|
||||
|
||||
userId, err := ctx.Values().GetInt("userId")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var resetPassword resetPasswordStruct
|
||||
if err := ctx.ReadJSON(&resetPassword); err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user := models.Users{
|
||||
ID: uint(userId),
|
||||
}
|
||||
result := database.DB.First(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("get user error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeUserNotExist, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !user.CheckPassword(resetPassword.OldPassword) {
|
||||
middleware.Error(ctx, middleware.CodePasswordError, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user.Password = user.PasswordHash(resetPassword.NewPassword)
|
||||
result = database.DB.Save(&user)
|
||||
if result.Error != nil {
|
||||
l.Error("save user error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeInternalPatchError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.Success(ctx)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/routers/api/v1/user/images"
|
||||
"megrez/routers/api/v1/user/instances"
|
||||
"megrez/routers/api/v1/user/servers"
|
||||
"megrez/services/logger"
|
||||
|
||||
_logger "megrez/libs/logger"
|
||||
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
)
|
||||
|
||||
var l *_logger.LoggerStruct
|
||||
|
||||
func InitUser(party router.Party) {
|
||||
l = logger.Logger.Clone()
|
||||
l.SetModel("Http.API.V1.User")
|
||||
|
||||
party.Use(middleware.Auth)
|
||||
|
||||
party.Post("/login", loginHandler)
|
||||
party.Get("/logout", middleware.AuthCheck, logoutHandler)
|
||||
party.Post("/register", registerHandler)
|
||||
party.Get("/profile", middleware.AuthCheck, profileHandler)
|
||||
party.Post("/resetPassword", middleware.AuthCheck, resetPasswordHandler)
|
||||
|
||||
servers.InitServers(party.Party("/servers"))
|
||||
instances.InitInstances(party.Party("/instances"))
|
||||
images.InitImages(party.Party("/images"))
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func detailHandler(ctx iris.Context) {
|
||||
l.SetFunction("detailHandler")
|
||||
|
||||
id, err := ctx.Params().GetUint("id")
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Servers{
|
||||
ID: id,
|
||||
}
|
||||
result := database.DB.Select("id", "name", "gpu_type", "gpu_num", "gpu_driver_version", "gpu_cuda_version", "cpu_count_per_gpu", "memory_per_gpu", "volume_total", "price", "price_volume", "gpu_used", "volume_used", "created_at").First(&server)
|
||||
if result.Error != nil {
|
||||
l.Error("detail server error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerDetailError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
redis.RawDB.Get(ctx, "remain_gpu:server:"+strconv.Itoa(int(id))).Scan(&server.GpuUsed)
|
||||
server.GpuUsed = server.GpuNum - server.GpuUsed
|
||||
|
||||
redis.RawDB.Get(ctx, "remain_volume:server:"+strconv.Itoa(int(id))).Scan(&server.VolumeUsed)
|
||||
server.VolumeUsed = server.VolumeTotal - server.VolumeUsed
|
||||
|
||||
middleware.Result(ctx, server)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"megrez/models"
|
||||
"megrez/routers/api/v1/middleware"
|
||||
"megrez/services/database"
|
||||
"megrez/services/redis"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func listHandler(ctx iris.Context) {
|
||||
l.SetFunction("serversHandler")
|
||||
var err error
|
||||
|
||||
offset := 0
|
||||
limit := 20
|
||||
offsetStr := ctx.URLParam("offset")
|
||||
limitStr := ctx.URLParam("limit")
|
||||
|
||||
if offsetStr != "" {
|
||||
offset, err = strconv.Atoi(offsetStr)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
if limitStr != "" {
|
||||
limit, err = strconv.Atoi(limitStr)
|
||||
if err != nil {
|
||||
middleware.Error(ctx, middleware.CodeBadRequest, iris.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var total int64
|
||||
var servers []models.Servers
|
||||
totalResult := database.DB.Model(&models.Servers{}).Count(&total)
|
||||
if totalResult.Error != nil {
|
||||
l.Error("list servers error: %v", totalResult.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerListError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
result := database.DB.Limit(limit).Offset(offset).Select("id", "name", "gpu_type", "gpu_num", "gpu_driver_version", "gpu_cuda_version", "cpu_count_per_gpu", "memory_per_gpu", "volume_total", "price", "price_volume", "gpu_used", "volume_used", "created_at").Order("id").Find(&servers)
|
||||
if result.Error != nil {
|
||||
l.Error("list servers error: %v", result.Error)
|
||||
middleware.Error(ctx, middleware.CodeAdminServerListError, iris.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
for i, server := range servers {
|
||||
redis.RawDB.Get(ctx, "remain_gpu:server:"+strconv.Itoa(int(server.ID))).Scan(&servers[i].GpuUsed)
|
||||
servers[i].GpuUsed = server.GpuNum - servers[i].GpuUsed
|
||||
|
||||
redis.RawDB.Get(ctx, "remain_volume:server:"+strconv.Itoa(int(server.ID))).Scan(&servers[i].VolumeUsed)
|
||||
servers[i].VolumeUsed = server.VolumeTotal - servers[i].VolumeUsed
|
||||
}
|
||||
|
||||
middleware.ResultWithTotal(ctx, servers, total)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package servers
|
||||
|
||||
import (
|
||||
"megrez/services/logger"
|
||||
|
||||
"github.com/kataras/iris/v12/core/router"
|
||||
|
||||
_logger "megrez/libs/logger"
|
||||
)
|
||||
|
||||
var l *_logger.LoggerStruct
|
||||
|
||||
func InitServers(party router.Party) {
|
||||
l = logger.Logger.Clone()
|
||||
l.SetModel("Http.API.V1.User.Servers")
|
||||
|
||||
party.Get("/", listHandler)
|
||||
party.Get("/{id:uint}", detailHandler)
|
||||
}
|
||||
Reference in New Issue
Block a user