[Init] 🎉 MEGREZ Community

This commit is contained in:
Harry-zklcdc
2024-12-29 01:02:31 +08:00
commit f2966d0f5c
172 changed files with 16348 additions and 0 deletions
+35
View File
@@ -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)
}
+48
View File
@@ -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)
}
+22
View File
@@ -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)
}
+104
View File
@@ -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)
}
+135
View File
@@ -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)
}
+61
View File
@@ -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)
}
+53
View File
@@ -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)
}
+49
View File
@@ -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)
}
+88
View File
@@ -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)
}
+128
View File
@@ -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)
}
+37
View File
@@ -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)
}
+20
View File
@@ -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"))
}
+56
View File
@@ -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)
}
+43
View File
@@ -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)
}
+39
View File
@@ -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)
}
+62
View File
@@ -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)
}
+84
View File
@@ -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)
}
+40
View File
@@ -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)
}
+1
View File
@@ -0,0 +1 @@
package users
+49
View File
@@ -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)
}
+31
View File
@@ -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)
}
+53
View File
@@ -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)
}
+65
View File
@@ -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)
}
+22
View File
@@ -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)
}
+87
View File
@@ -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",
}
+71
View File
@@ -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()
}
+41
View File
@@ -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,
})
}
+12
View File
@@ -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"`
}
+13
View File
@@ -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"))
}
+14
View File
@@ -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
})
}
+35
View File
@@ -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)
}
+20
View File
@@ -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)
}
+99
View File
@@ -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)
}
+141
View File
@@ -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)
}
+65
View File
@@ -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)
}
+61
View File
@@ -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)
}
+55
View File
@@ -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)
}
+85
View File
@@ -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)
}
+134
View File
@@ -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)
}
+38
View File
@@ -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)
}
+71
View File
@@ -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)
}
+26
View File
@@ -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)
}
+1
View File
@@ -0,0 +1 @@
package user
+46
View File
@@ -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)
}
+52
View File
@@ -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)
}
+55
View File
@@ -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)
}
+32
View File
@@ -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"))
}
+39
View File
@@ -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)
}
+62
View File
@@ -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)
}
+19
View File
@@ -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)
}