#4981 合并资源规格管理功能到里程碑分支

Merged
ychao_1983 merged 31 commits from pool-update-new2 into V20231211 4 months ago
  1. +17
    -15
      entity/cluster.go
  2. +4
    -1
      models/card_request.go
  3. +33
    -4
      models/cloudbrain.go
  4. +4
    -0
      models/cloudbrain_spec.go
  5. +1
    -0
      models/models.go
  6. +37
    -38
      models/resource_queue.go
  7. +208
    -69
      models/resource_scene.go
  8. +78
    -37
      models/resource_specification.go
  9. +49
    -2
      modules/grampus/resty.go
  10. +30
    -5
      routers/admin/resources.go
  11. +100
    -17
      services/ai_task_service/cluster/c2net.go
  12. +1
    -10
      services/ai_task_service/cluster/cloudbrain_two.go
  13. +1
    -0
      services/ai_task_service/context/context.go
  14. +3
    -11
      services/ai_task_service/task/cloudbrain_one_notebook_task.go
  15. +2
    -58
      services/ai_task_service/task/cloudbrain_one_train_task.go
  16. +3
    -28
      services/ai_task_service/task/cloudbrain_two_train_task.go
  17. +2
    -10
      services/ai_task_service/task/grampus_notebook_task.go
  18. +2
    -10
      services/ai_task_service/task/grampus_online_infer_task.go
  19. +2
    -58
      services/ai_task_service/task/grampus_train_task.go
  20. +10
    -0
      services/ai_task_service/task/opt_handler.go
  21. +9
    -2
      services/ai_task_service/task/task_extend.go
  22. +1
    -44
      services/ai_task_service/task/task_service.go
  23. +43
    -47
      services/cloudbrain/resource/resource_queue.go
  24. +1
    -0
      services/cloudbrain/resource/resource_scene.go
  25. +8
    -0
      services/cloudbrain/resource/resource_specification.go
  26. +1
    -1
      templates/admin/navbar.tmpl
  27. +3
    -0
      templates/computingpower/domestic.tmpl
  28. +5
    -3
      web_src/vuepages/apis/modules/resources.js
  29. +17
    -10
      web_src/vuepages/langs/config/en-US.js
  30. +14
    -7
      web_src/vuepages/langs/config/zh-CN.js
  31. +3
    -0
      web_src/vuepages/pages/computingpower/domestic/index.vue
  32. +23
    -1
      web_src/vuepages/pages/resources/components/QueueDialog.vue
  33. +33
    -13
      web_src/vuepages/pages/resources/components/SceneDialog.vue
  34. +24
    -12
      web_src/vuepages/pages/resources/components/SpecSelect.vue
  35. +3
    -1
      web_src/vuepages/pages/resources/components/SpecificationDialog.vue
  36. +26
    -8
      web_src/vuepages/pages/resources/queue/index.vue
  37. +52
    -20
      web_src/vuepages/pages/resources/scene/index.vue
  38. +18
    -11
      web_src/vuepages/pages/resources/specification/index.vue

+ 17
- 15
entity/cluster.go View File

@@ -25,7 +25,7 @@ type NoteBookTask struct {
AutoStopDuration int64
Name string
Capacity int
CenterID []string
Queues []models.ResourceQueue
Code []ContainerData
Datasets []ContainerData
PreTrainModel []ContainerData
@@ -73,6 +73,7 @@ type QueryTaskResponse struct {
Token string `json:"token"`
CenterId string `json:"center_id"`
CenterName string `json:"center_name"`
QueueCode string `json:"queue_code"`
CodeUrl string `json:"code_url"`
DataUrl string `json:"data_url"`
ContainerIP string `json:"container_ip"`
@@ -108,6 +109,7 @@ func ConvertGrampusNotebookResponse(job models.GrampusNotebookInfo) *QueryTaskRe
DetailedStatus: job.DetailedStatus,
CenterId: centerId,
CenterName: centerName,
QueueCode: task.PoolId,
Url: url,
Token: token,
JobId: job.JobID,
@@ -212,20 +214,20 @@ type ClusterLog struct {
}

type TrainTask struct {
Command string `json:"command"`
Name string `json:"name"`
ImageId string `json:"imageId"`
ImageUrl string `json:"imageUrl"`
ResourceSpecId string `json:"resourceSpecId"`
CenterID []string `json:"centerID"`
ReplicaNum int `json:"replicaNum"`
Datasets []ContainerData `json:"datasets"`
PreTrainModel []ContainerData `json:"models"`
Code []ContainerData `json:"code"`
BootFile string `json:"bootFile"`
OutPut []ContainerData `json:"output"`
LogPath []ContainerData `json:"logPath"`
PoolId string `json:"poolId"`
Command string `json:"command"`
Name string `json:"name"`
ImageId string `json:"imageId"`
ImageUrl string `json:"imageUrl"`
ResourceSpecId string `json:"resourceSpecId"`
Queues []models.ResourceQueue `json:"centerID"`
ReplicaNum int `json:"replicaNum"`
Datasets []ContainerData `json:"datasets"`
PreTrainModel []ContainerData `json:"models"`
Code []ContainerData `json:"code"`
BootFile string `json:"bootFile"`
OutPut []ContainerData `json:"output"`
LogPath []ContainerData `json:"logPath"`
PoolId string `json:"poolId"`
Params models.Parameters
Spec *models.Specification
RepoName string


+ 4
- 1
models/card_request.go View File

@@ -143,6 +143,8 @@ type RequestSpecInfo struct {
AiCenterCode string
AiCenterName string
QueueCode string
QueueName string
QueueType string
QueueId int64
ComputeResource string
AccCardType string
@@ -402,7 +404,8 @@ func SearchCardRequest(opts *CardRequestOptions) (int64, []*CardRequestSpecRes,
"card_request_spec.request_id", "resource_queue.cluster",
"resource_queue.ai_center_code", "resource_queue.acc_card_type",
"resource_queue.id as queue_id", "resource_queue.compute_resource",
"resource_queue.queue_code", "resource_queue.ai_center_name",
"resource_queue.queue_code", "resource_queue.queue_name",
"resource_queue.queue_type", "resource_queue.ai_center_name",
"resource_queue.has_internet",
).In("card_request_spec.request_id", requestIds).
Join("INNER", "card_request_spec", "card_request_spec.spec_id = resource_specification.id").


+ 33
- 4
models/cloudbrain.go View File

@@ -271,6 +271,7 @@ type Cloudbrain struct {
EngineID int64 //引擎id
ImageID string //grampus image_id
AiCenter string //grampus ai center: center_id+center_name
QueueCode string
FailedReason string `xorm:"text"`

TrainUrl string //输出模型的obs路径
@@ -1869,9 +1870,24 @@ type GrampusNotebookInfo struct {
UserID string `json:"userId"`
Tasks []GrampusNotebookTask `json:"tasks"`
}

const (
GrampusNetAccess = "1"
GrampusNotNetAccess = "2"

GrampusPoolTypePublic = "1"
GrampusPoolTypeExclusive = "2"
)

type Center struct {
ID string `json:"id"`
Name string `json:"name"`
ID string `json:"id"`
Name string `json:"name"`
ResourceSpec []struct {
ID string `json:"id"`
PoolType string `json:"poolType"`
Name string `json:"name"`
IsNetAccess string `json:"isNetAccess"`
} `json:"resourceSpec"`
}
type GrampusSpec struct {
CreatedAt int64 `json:"createdAt"`
@@ -1925,9 +1941,21 @@ type GetGrampusResourceSpecsResult struct {

type GetGrampusAiCentersResult struct {
GrampusResult
Infos []GrampusAiCenter `json:"aiCenterInfos"`
TotalSize int `json:"totalSize"`
Infos []GrampusAiCenter `json:"aiCenterInfos"`
}

type GrampusResourceQueue struct {
QueueCode string
QueueName string
QueueType string
AiCenterCode string
AiCenterName string
ComputeResource string
AccCardType string
HasInternet int //0 unknown;1 no internet;2 has internet

}

type AICenterImage struct {
AICenterID string `json:"aiCenterId"`
ImageUrl string `json:"imageUrl"`
@@ -2028,6 +2056,7 @@ type GrampusNotebookTask struct {
Capacity int `json:"capacity"`
CenterID []string `json:"centerID"`
CenterName []string `json:"centerName"`
PoolId string `json:"poolId"`
Code GrampusDataset `json:"code"`
Datasets []GrampusDataset `json:"datasets"`
OutPut GrampusDataset `json:"output"`


+ 4
- 0
models/cloudbrain_spec.go View File

@@ -18,6 +18,8 @@ type CloudbrainSpec struct {
UnitPrice int
QueueId int64
QueueCode string
QueueName string
QueueType string
Cluster string
HasInternet int
AiCenterCode string `xorm:"index"`
@@ -163,6 +165,8 @@ func UpdateCloudbrainSpec(cloudbrainId int64, s *Specification) (int64, error) {
UnitPrice: s.UnitPrice,
QueueId: s.QueueId,
QueueCode: s.QueueCode,
QueueName: s.QueueName,
QueueType: s.QueueType,
Cluster: s.Cluster,
AiCenterCode: s.AiCenterCode,
AiCenterName: s.AiCenterName,


+ 1
- 0
models/models.go View File

@@ -177,6 +177,7 @@ func init() {
new(ModelartsDeploy),
new(ModelartsDeployQueue),
new(CloudbrainConfig),
new(ResourceExclusivePool),
new(CardRequest),
new(CardRequestSpec),
)


+ 37
- 38
models/resource_queue.go View File

@@ -2,18 +2,23 @@ package models

import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"encoding/json"
"errors"
"strconv"
"strings"
"xorm.io/builder"
)

const (
QueueTypePublic = "public"
QueueTypeExclusive = "exclusive"
)

type ResourceQueue struct {
ID int64 `xorm:"pk autoincr"`
QueueCode string
QueueName string
QueueType string
Cluster string `xorm:"notnull"`
AiCenterCode string
AiCenterName string
@@ -34,6 +39,8 @@ func (r ResourceQueue) ConvertToRes() *ResourceQueueRes {
return &ResourceQueueRes{
ID: r.ID,
QueueCode: r.QueueCode,
QueueName: r.QueueName,
QueueType: r.QueueType,
Cluster: r.Cluster,
AiCenterCode: r.AiCenterCode,
AiCenterName: r.AiCenterName,
@@ -57,6 +64,8 @@ type ResourceQueueReq struct {
CreatorId int64
IsAutomaticSync bool
Remark string
QueueName string
QueueType string
}

func (r ResourceQueueReq) ToDTO() ResourceQueue {
@@ -72,6 +81,8 @@ func (r ResourceQueueReq) ToDTO() ResourceQueue {
Remark: r.Remark,
CreatedBy: r.CreatorId,
UpdatedBy: r.CreatorId,
QueueName: r.QueueName,
QueueType: r.QueueType,
}
if r.Cluster == OpenICluster {
if r.AiCenterCode == AICenterOfCloudBrainOne {
@@ -92,6 +103,7 @@ type SearchResourceQueueOptions struct {
ComputeResource string
AccCardType string
HasInternet SpecInternetQuery
QueueType string
}

type ResourceQueueListRes struct {
@@ -102,6 +114,8 @@ type ResourceQueueListRes struct {
type ResourceQueueCodesRes struct {
ID int64
QueueCode string
QueueName string
QueueType string
Cluster string
AiCenterCode string
AiCenterName string
@@ -136,6 +150,8 @@ func NewResourceQueueListRes(totalSize int64, list []ResourceQueue) *ResourceQue
type ResourceQueueRes struct {
ID int64
QueueCode string
QueueType string
QueueName string
Cluster string
AiCenterCode string
AiCenterName string
@@ -155,7 +171,7 @@ func UpdateResourceQueueById(queueId int64, queue ResourceQueue) (int64, error)
return x.ID(queueId).Update(&queue)
}
func UpdateResourceCardsTotalNumAndInternetStatus(queueId int64, queue ResourceQueue) (int64, error) {
return x.ID(queueId).Cols("cards_total_num", "remark", "has_internet").Update(&queue)
return x.ID(queueId).Cols("cards_total_num", "remark", "has_internet", "queue_type", "queue_name").Update(&queue)
}

func SearchResourceQueue(opts SearchResourceQueueOptions) (int64, []ResourceQueue, error) {
@@ -180,6 +196,9 @@ func SearchResourceQueue(opts SearchResourceQueueOptions) (int64, []ResourceQueu
} else if opts.HasInternet == QueryHasInternetSpecs {
cond = cond.And(builder.Eq{"has_internet": HasInternet})
}
if opts.QueueType != "" {
cond = cond.And(builder.Eq{"queue_type": opts.QueueType})
}
n, err := x.Where(cond).Unscoped().Count(&ResourceQueue{})
if err != nil {
return 0, nil, err
@@ -366,39 +385,15 @@ func GetResourceAiCenters() ([]ResourceAiCenterRes, error) {
return r, nil
}

type SpecificationSpecialQueueConfig struct {
SpecialQueues []SpecialQueue `json:"special_queues"`
}

type SpecialQueue struct {
OrgName string `json:"org_name"`
JobType string `json:"job_type"`
Cluster string `json:"cluster"`
QueueId int64 `json:"queue_id"`
ComputeResource string `json:"compute_resource"`
}

var specialQueueConfig SpecificationSpecialQueueConfig
var specialQueueConfigFlag = false

func GetSpecialQueueConfig() SpecificationSpecialQueueConfig {
if !specialQueueConfigFlag {
if err := json.Unmarshal([]byte(setting.SPECIFICATION_SPECIAL_QUEUE), &specialQueueConfig); err != nil {
log.Error("json.Unmarshal specialQueueConfig error.%v", err)
}
specialQueueConfigFlag = true
}
return specialQueueConfig
}

func GetSpecialQueueIds(opts FindSpecsOptions) []SpecialQueue {
config := GetSpecialQueueConfig()
if len(config.SpecialQueues) == 0 {
return []SpecialQueue{}
func GetExclusiveQueueIds(opts FindSpecsOptions) []*ResourceExclusivePool {
pools, err := FindExclusivePools()
if err != nil {
log.Error("GetSpecialQueueIds FindSpecialQueueConfig err.%v", err)
return nil
}

queues := make([]SpecialQueue, 0)
for _, queue := range config.SpecialQueues {
queues := make([]*ResourceExclusivePool, 0)
for _, queue := range pools {
if queue.JobType != string(opts.JobType) {
continue
}
@@ -414,18 +409,22 @@ func GetSpecialQueueIds(opts FindSpecsOptions) []SpecialQueue {
return queues
}

func IsUserInSpecialPool(userId int64) bool {
func IsUserInExclusivePool(userId int64) bool {
userOrgs, err := GetOrgsByUserID(userId, true)
if err != nil {
log.Error("GetSpecialQueueIds GetOrgsByUserID error.%v", err)
return false
}
config := GetSpecialQueueConfig()
if len(config.SpecialQueues) == 0 {
pools, err := FindExclusivePools()
if err != nil {
log.Error("IsUserInSpecialPool FindExclusivePools err.%v", err)
return false
}
if len(pools) == 0 {
return false
}
for _, org := range userOrgs {
for _, queue := range config.SpecialQueues {
for _, queue := range pools {
if strings.ToLower(org.Name) == strings.ToLower(queue.OrgName) {
return true
}


+ 208
- 69
models/resource_scene.go View File

@@ -1,8 +1,10 @@
package models

import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"errors"
"strings"
"xorm.io/builder"
)

@@ -11,18 +13,29 @@ const (
NotExclusive
)

const (
SceneTypePublic = "public"
SceneTypeExclusive = "exclusive"

SpecPublic = "public"
SpecExclusive = "exclusive"
)

type ResourceScene struct {
ID int64 `xorm:"pk autoincr"`
SceneName string
JobType string
IsExclusive bool
ExclusiveOrg string
CreatedTime timeutil.TimeStamp `xorm:"created"`
CreatedBy int64
UpdatedTime timeutil.TimeStamp `xorm:"updated"`
UpdatedBy int64
DeleteTime timeutil.TimeStamp `xorm:"deleted"`
DeletedBy int64
ID int64 `xorm:"pk autoincr"`
SceneName string
JobType string
Cluster string
ComputeResource string
IsSpecExclusive string
SceneType string //共享或者独占场景
ExclusiveOrg string
CreatedTime timeutil.TimeStamp `xorm:"created"`
CreatedBy int64
UpdatedTime timeutil.TimeStamp `xorm:"updated"`
UpdatedBy int64
DeleteTime timeutil.TimeStamp `xorm:"deleted"`
DeletedBy int64
}

type ResourceSceneSpec struct {
@@ -32,26 +45,47 @@ type ResourceSceneSpec struct {
CreatedTime timeutil.TimeStamp `xorm:"created"`
}

type ResourceExclusivePool struct {
ID int64 `xorm:"pk autoincr"`
SceneId int64
OrgName string
JobType string
Cluster string
QueueId int64
ComputeResource string
CreatedTime timeutil.TimeStamp `xorm:"created"`
CreatedBy int64
UpdatedTime timeutil.TimeStamp `xorm:"updated"`
UpdatedBy int64
DeleteTime timeutil.TimeStamp `xorm:"deleted"`
DeletedBy int64
}

type ResourceSceneReq struct {
ID int64
SceneName string
JobType string
IsExclusive bool
ExclusiveOrg string
CreatorId int64
SpecIds []int64
ID int64
SceneName string
JobType string
SceneType string
Cluster string
Resource string
ExclusiveQueueIds []int64
IsSpecExclusive string
ExclusiveOrg string
CreatorId int64
SpecIds []int64
}

type SearchResourceSceneOptions struct {
ListOptions
JobType string
IsExclusive int
IsSpecExclusive string
AiCenterCode string
QueueId int64
ComputeResource string
AccCardType string
Cluster string
HasInternet SpecInternetQuery
SceneType string
}

type ResourceSceneListRes struct {
@@ -67,12 +101,15 @@ func NewResourceSceneListRes(totalSize int64, list []ResourceSceneRes) *Resource
}

type ResourceSceneRes struct {
ID int64
SceneName string
JobType JobType
IsExclusive bool
ExclusiveOrg string
Specs []ResourceSpecInfo
ID int64
SceneName string
JobType JobType
IsSpecExclusive string
Cluster string
ComputeResource string
SceneType string //共享或者独占场景
ExclusiveOrg string
Specs []ResourceSpecInfo
}

func (ResourceSceneRes) TableName() string {
@@ -105,6 +142,8 @@ type ResourceSpecInfo struct {
AiCenterCode string
AiCenterName string
QueueCode string
QueueType string
QueueName string
QueueId int64
ComputeResource string
AccCardType string
@@ -119,6 +158,11 @@ func InsertResourceScene(r ResourceSceneReq) error {
sess := x.NewSession()
defer sess.Close()

err := sess.Begin()
if err != nil {
log.Error("InsertResourceScene start transaction err. %v", err)
return err
}
//check
specs := make([]ResourceSpecification, 0)
cond := builder.In("id", r.SpecIds)
@@ -130,34 +174,68 @@ func InsertResourceScene(r ResourceSceneReq) error {
}

rs := ResourceScene{
SceneName: r.SceneName,
JobType: r.JobType,
IsExclusive: r.IsExclusive,
ExclusiveOrg: r.ExclusiveOrg,
CreatedBy: r.CreatorId,
UpdatedBy: r.CreatorId,
}
_, err := sess.InsertOne(&rs)
SceneName: r.SceneName,
JobType: r.JobType,
IsSpecExclusive: r.IsSpecExclusive,
SceneType: r.SceneType,
Cluster: r.Cluster,
ComputeResource: r.Resource,
ExclusiveOrg: r.ExclusiveOrg,
CreatedBy: r.CreatorId,
UpdatedBy: r.CreatorId,
}
_, err = sess.InsertOne(&rs)
if err != nil {
sess.Rollback()
return err
}

if len(r.SpecIds) == 0 {
return sess.Commit()
}
rss := make([]ResourceSceneSpec, len(r.SpecIds))
for i, v := range r.SpecIds {
rss[i] = ResourceSceneSpec{
SceneId: rs.ID,
SpecId: v,
if len(r.SpecIds) > 0 {
rss := make([]ResourceSceneSpec, len(r.SpecIds))
for i, v := range r.SpecIds {
rss[i] = ResourceSceneSpec{
SceneId: rs.ID,
SpecId: v,
}
}

_, err = sess.Insert(&rss)
if err != nil {
sess.Rollback()
return err
}
}

_, err = sess.Insert(&rss)
if err != nil {
sess.Rollback()
return err
if r.SceneType == SceneTypeExclusive && r.ExclusiveOrg != "" && len(r.SpecIds) > 0 {
pools := make([]ResourceExclusivePool, 0)
queueIds := make([]int64, 0)
err = sess.Table("resource_specification").Distinct("queue_id").In("id", r.SpecIds).Find(&queueIds)
if err != nil {
sess.Rollback()
return err
}
for _, org := range strings.Split(r.ExclusiveOrg, ";") {
if org == "" {
continue
}
for _, id := range queueIds {
pools = append(pools, ResourceExclusivePool{
SceneId: rs.ID,
OrgName: org,
JobType: r.JobType,
Cluster: r.Cluster,
QueueId: id,
ComputeResource: r.Resource,
CreatedBy: r.CreatorId,
UpdatedBy: r.CreatorId,
})
}
}
_, err = sess.Insert(pools)
if err != nil {
sess.Rollback()
return err
}
}

return sess.Commit()
@@ -172,7 +250,11 @@ func UpdateResourceScene(r ResourceSceneReq) error {
}
sess.Close()
}()

err = sess.Begin()
if err != nil {
log.Error("UpdateResourceScene start transaction err. %v", err)
return err
}
// find old scene
old := ResourceScene{}
if has, _ := sess.ID(r.ID).Get(&old); !has {
@@ -190,36 +272,69 @@ func UpdateResourceScene(r ResourceSceneReq) error {

//update scene
rs := ResourceScene{
SceneName: r.SceneName,
IsExclusive: r.IsExclusive,
ExclusiveOrg: r.ExclusiveOrg,
SceneName: r.SceneName,
IsSpecExclusive: r.IsSpecExclusive,
ExclusiveOrg: r.ExclusiveOrg,
SceneType: r.SceneType,
}
if _, err = sess.ID(r.ID).UseBool("is_exclusive").Update(&rs); err != nil {
if _, err = sess.ID(r.ID).UseBool("is_spec_exclusive").Update(&rs); err != nil {
return err
}

//delete scene spec relation
if _, err = sess.Where("scene_id = ? ", r.ID).Delete(&ResourceSceneSpec{}); err != nil {
sess.Rollback()
return err
}

if len(r.SpecIds) == 0 {
return sess.Commit()
}
//build new scene spec relation
rss := make([]ResourceSceneSpec, len(r.SpecIds))
for i, v := range r.SpecIds {
rss[i] = ResourceSceneSpec{
SceneId: r.ID,
SpecId: v,
if len(r.SpecIds) > 0 {
//build new scene spec relation
rss := make([]ResourceSceneSpec, len(r.SpecIds))
for i, v := range r.SpecIds {
rss[i] = ResourceSceneSpec{
SceneId: r.ID,
SpecId: v,
}
}
if _, err = sess.Insert(&rss); err != nil {
return err
}

}
if _, err = sess.Insert(&rss); err != nil {
sess.Rollback()
if _, err = sess.Where("scene_id = ? ", r.ID).Delete(&ResourceExclusivePool{}); err != nil {
return err
}

if r.SceneType == SceneTypeExclusive && r.ExclusiveOrg != "" && len(r.SpecIds) > 0 {
pools := make([]ResourceExclusivePool, 0)
queueIds := make([]int64, 0)
err = sess.Table("resource_specification").Distinct("queue_id").In("id", r.SpecIds).Find(&queueIds)
if err != nil {
return err
}
for _, org := range strings.Split(r.ExclusiveOrg, ";") {
if org == "" {
continue
}
for _, id := range queueIds {
pools = append(pools, ResourceExclusivePool{
SceneId: r.ID,
OrgName: org,
JobType: r.JobType,
Cluster: r.Cluster,
QueueId: id,
ComputeResource: r.Resource,
CreatedBy: r.CreatorId,
UpdatedBy: r.CreatorId,
})
}
}
_, err = sess.Insert(pools)
if err != nil {
return err
}
}

return sess.Commit()
}

@@ -232,6 +347,11 @@ func DeleteResourceScene(sceneId int64) error {
}
sess.Close()
}()
err = sess.Begin()
if err != nil {
log.Error("DeleteResourceScene start transaction err. %v", err)
return err
}

if _, err = sess.ID(sceneId).Delete(&ResourceScene{}); err != nil {
return err
@@ -239,6 +359,9 @@ func DeleteResourceScene(sceneId int64) error {
if _, err = sess.Where("scene_id = ? ", sceneId).Delete(&ResourceSceneSpec{}); err != nil {
return err
}
if _, err = sess.Where("scene_id = ? ", sceneId).Delete(&ResourceExclusivePool{}); err != nil {
return err
}
return sess.Commit()
}

@@ -250,10 +373,8 @@ func SearchResourceScene(opts SearchResourceSceneOptions) (int64, []ResourceScen
if opts.JobType != "" {
cond = cond.And(builder.Eq{"resource_scene.job_type": opts.JobType})
}
if opts.IsExclusive == Exclusive {
cond = cond.And(builder.Eq{"resource_scene.is_exclusive": 1})
} else if opts.IsExclusive == NotExclusive {
cond = cond.And(builder.Eq{"resource_scene.is_exclusive": 0})
if opts.IsSpecExclusive != "" {
cond = cond.And(builder.Eq{"resource_scene.is_spec_exclusive": opts.IsSpecExclusive})
}
if opts.AiCenterCode != "" {
cond = cond.And(builder.Eq{"resource_queue.ai_center_code": opts.AiCenterCode})
@@ -275,9 +396,12 @@ func SearchResourceScene(opts SearchResourceSceneOptions) (int64, []ResourceScen
} else if opts.HasInternet == QueryNoInternetSpecs {
cond = cond.And(builder.Eq{"resource_queue.has_internet": NoInternet})
}
if opts.SceneType != "" {
cond = cond.And(builder.Eq{"resource_scene.scene_type": opts.SceneType})
}
cond = cond.And(builder.NewCond().Or(builder.Eq{"resource_scene.delete_time": 0}).Or(builder.IsNull{"resource_scene.delete_time"}))
cols := []string{"resource_scene.id", "resource_scene.scene_name", "resource_scene.job_type", "resource_scene.is_exclusive",
"resource_scene.exclusive_org"}
cols := []string{"resource_scene.id", "resource_scene.scene_name", "resource_scene.job_type", "resource_scene.is_spec_exclusive",
"resource_scene.exclusive_org", "resource_scene.scene_type", "resource_scene.cluster", "resource_scene.compute_resource"}
count, err := x.Where(cond).
Distinct("resource_scene.id").
Join("INNER", "resource_scene_spec", "resource_scene_spec.scene_id = resource_scene.id").
@@ -302,6 +426,7 @@ func SearchResourceScene(opts SearchResourceSceneOptions) (int64, []ResourceScen
if len(r) == 0 {
return 0, r, err
}

//find related specs
sceneIds := make([]int64, 0, len(r))
for _, v := range r {
@@ -319,7 +444,7 @@ func SearchResourceScene(opts SearchResourceSceneOptions) (int64, []ResourceScen
"resource_queue.ai_center_code", "resource_queue.acc_card_type",
"resource_queue.id as queue_id", "resource_queue.compute_resource",
"resource_queue.queue_code", "resource_queue.ai_center_name",
"resource_queue.has_internet",
"resource_queue.has_internet", "resource_queue.queue_name", "resource_queue.queue_type",
).In("resource_scene_spec.scene_id", sceneIds).
Join("INNER", "resource_scene_spec", "resource_scene_spec.spec_id = resource_specification.id").
Join("INNER", "resource_queue", "resource_queue.ID = resource_specification.queue_id").
@@ -347,3 +472,17 @@ func SearchResourceScene(opts SearchResourceSceneOptions) (int64, []ResourceScen

return count, r, nil
}

func FindExclusivePools() ([]*ResourceExclusivePool, error) {
sq := make([]*ResourceExclusivePool, 0)

err := x.Find(&sq)
if err != nil {
return nil, err
}
return sq, nil
}

func InsertExclusivePools(queue []ResourceExclusivePool) (int64, error) {
return x.Insert(&queue)
}

+ 78
- 37
models/resource_specification.go View File

@@ -193,6 +193,8 @@ func (r ResourceSpecAndQueue) ConvertToResourceSpecInfo() *ResourceSpecInfo {
AiCenterCode: r.AiCenterCode,
AiCenterName: r.AiCenterName,
QueueCode: r.QueueCode,
QueueType: r.QueueType,
QueueName: r.QueueName,
QueueId: r.QueueId,
ComputeResource: r.ComputeResource,
AccCardType: r.AccCardType,
@@ -223,6 +225,7 @@ type FindSpecsOptions struct {
RequestAll bool
SpecStatus int
HasInternet SpecInternetQuery //0 all,1 no internet,2 has internet
SceneType string
}

type Specification struct {
@@ -238,48 +241,37 @@ type Specification struct {
UnitPrice int
QueueId int64
QueueCode string
QueueName string
QueueType string
HasInternet int
Cluster string
AiCenterCode string
AiCenterName string
IsExclusive bool
ExclusiveOrg string
//specs that have the same sourceSpecId, computeResource and cluster as current spec
RelatedSpecs []*Specification
}

func (Specification) TableName() string {
return "resource_specification"
}

func (s *Specification) loadRelatedSpecs(jobType JobType, hasInternet SpecInternetQuery) {
if s.RelatedSpecs != nil {
return
}
func (s *Specification) findRelatedSpecs(opts FindSpecsOptions, userId int64) []*Specification {
defaultSpecs := make([]*Specification, 0)
if s.SourceSpecId == "" {
s.RelatedSpecs = defaultSpecs
return
return defaultSpecs
}
//是否需要网络的调度策略如下:
//需要联网时只能调度到有网的分中心;不需要联网时可以调度到所有的分中心
if hasInternet == QueryNoInternetSpecs {
hasInternet = QueryAllSpecs
isUserSpecial := IsUserInExclusivePool(userId)
if isUserSpecial {
opts.SceneType = SceneTypeExclusive
} else {
opts.SceneType = SceneTypePublic
}
r, err := FindSpecs(FindSpecsOptions{
ComputeResource: s.ComputeResource,
Cluster: s.Cluster,
SourceSpecId: s.SourceSpecId,
RequestAll: false,
SpecStatus: SpecOnShelf,
JobType: jobType,
HasInternet: hasInternet,
})

r, err := FindSpecs(opts)
if err != nil {
s.RelatedSpecs = defaultSpecs
return
return defaultSpecs
}
s.RelatedSpecs = r
return r
}

func (s *Specification) ToShowString() string {
@@ -297,6 +289,22 @@ func (s *Specification) ToShowString() string {
return specName
}

func (s *Specification) ParseResourceQueue() ResourceQueue {
return ResourceQueue{
ID: s.QueueId,
QueueCode: s.QueueCode,
QueueName: s.QueueName,
QueueType: s.QueueType,
Cluster: s.Cluster,
AiCenterCode: s.AiCenterCode,
AiCenterName: s.AiCenterName,
ComputeResource: s.ComputeResource,
AccCardType: s.AccCardType,
CardsTotalNum: s.AccCardsNum,
HasInternet: s.HasInternet,
}
}

func GetAvailableCenterIdsByASpec(ID int64) ([]string, error) {
spec, err := GetResourceSpecification(&ResourceSpecification{
ID: ID})
@@ -321,14 +329,39 @@ type GetAvailableCenterIdOpts struct {
}

func (s *Specification) GetAvailableCenterIds(opts GetAvailableCenterIdOpts) []string {
s.loadRelatedSpecs(opts.JobType, opts.HasInternet)
queues := s.GetAvailableQueues(opts)
centerIds := make([]string, 0)
for _, v := range queues {
centerIds = append(centerIds, v.AiCenterCode)
}
return centerIds
}

func (s *Specification) GetAvailableQueues(opts GetAvailableCenterIdOpts) []ResourceQueue {
//是否需要网络的调度策略如下:
//需要联网时只能调度到有网的分中心;不需要联网时可以调度到所有的分中心
hasInternet := opts.HasInternet
if hasInternet == QueryNoInternetSpecs {
hasInternet = QueryAllSpecs
}

specOpts := FindSpecsOptions{
ComputeResource: s.ComputeResource,
Cluster: s.Cluster,
SourceSpecId: s.SourceSpecId,
RequestAll: false,
SpecStatus: SpecOnShelf,
JobType: opts.JobType,
HasInternet: hasInternet,
}
relatedSpecs := s.findRelatedSpecs(specOpts, opts.UserId)

if len(s.RelatedSpecs) == 0 {
return make([]string, 0)
if len(relatedSpecs) == 0 {
return make([]ResourceQueue, 0)
}

//filter exclusive specs
specs := FilterExclusiveSpecs(s.RelatedSpecs, opts.UserId)
specs := FilterExclusiveSpecs(relatedSpecs, opts.UserId)

specs = HandleSpecialQueues(specs, opts.UserId, FindSpecsOptions{
JobType: opts.JobType,
@@ -336,11 +369,16 @@ func (s *Specification) GetAvailableCenterIds(opts GetAvailableCenterIdOpts) []s
ComputeResource: s.ComputeResource,
})

centerIds := make([]string, len(specs))
for i, v := range specs {
centerIds[i] = v.AiCenterCode
queueMap := make(map[int64]string, len(specs))
queues := make([]ResourceQueue, 0)
for _, v := range specs {
if _, ok := queueMap[v.QueueId]; ok {
continue
}
queues = append(queues, v.ParseResourceQueue())
queueMap[v.QueueId] = ""
}
return centerIds
return queues
}

func FilterExclusiveSpecs(r []*Specification, userId int64) []*Specification {
@@ -408,17 +446,17 @@ func HandleSpecialQueues(specs []*Specification, userId int64, opts FindSpecsOpt
if len(specs) == 0 {
return specs
}
isUserInSpecialPool := IsUserInSpecialPool(userId)
isUserInSpecialPool := IsUserInExclusivePool(userId)
if isUserInSpecialPool {
specs = handleSpecialUserSpecs(specs, userId, opts)
specs = handleExclusiveUserSpecs(specs, userId, opts)
} else {
specs = handleNormalUserSpecs(specs, opts)
}
return specs
}

func handleSpecialUserSpecs(specs []*Specification, userId int64, opts FindSpecsOptions) []*Specification {
specialQueues := GetSpecialQueueIds(opts)
func handleExclusiveUserSpecs(specs []*Specification, userId int64, opts FindSpecsOptions) []*Specification {
specialQueues := GetExclusiveQueueIds(opts)
userOrgs, err := GetOrgsByUserID(userId, true)
if err != nil {
log.Error("handleSpecialUserSpecs GetOrgsByUserID error.%v", err)
@@ -437,7 +475,7 @@ func handleSpecialUserSpecs(specs []*Specification, userId int64, opts FindSpecs
}

func handleNormalUserSpecs(specs []*Specification, opts FindSpecsOptions) []*Specification {
queues := GetSpecialQueueIds(opts)
queues := GetExclusiveQueueIds(opts)
queueIds := make([]int64, 0)
for _, queue := range queues {
queueIds = append(queueIds, queue.QueueId)
@@ -687,6 +725,9 @@ func FindSpecs(opts FindSpecsOptions) ([]*Specification, error) {
} else if opts.HasInternet == QueryHasInternetSpecs {
cond = cond.And(builder.Eq{"resource_queue.has_internet": HasInternet})
}
if opts.SceneType != "" {
cond = cond.And(builder.Eq{"resource_scene.scene_type": opts.SceneType})
}

r := make([]*Specification, 0)
s := x.Where(cond).


+ 49
- 2
modules/grampus/resty.go View File

@@ -238,11 +238,11 @@ func GetResourceSpecs(processorType string) (*models.GetGrampusResourceSpecsResu
retry := 0

sendjob:
_, err := client.R().
res, err := client.R().
SetAuthToken(TOKEN).
SetResult(&result).
Get(HOST + urlGetResourceSpecs + "?processorType=" + processorType)
log.Info("%+v", res)
if err != nil {
return nil, fmt.Errorf("resty GetResourceSpecs: %v", err)
}
@@ -503,6 +503,53 @@ sendjob:
return &result, nil
}

func GetResourceQueue() ([]models.GrampusResourceQueue, error) {
res, err := GetResourceSpecs("")
if err != nil {
return nil, err
}
queueList := make([]models.GrampusResourceQueue, 0)
queueMap := make(map[string]string, 0)
for _, spec := range res.Infos {
for _, c := range spec.Centers {
centerId := c.ID
computeResource := models.ParseComputeResourceFormGrampus(spec.SpecInfo.AccDeviceKind)
if centerId == "" || computeResource == "" {
continue
}
for _, queue := range c.ResourceSpec {
queueCode := queue.ID
accCardType := strings.ToUpper(spec.SpecInfo.AccDeviceModel)
key := centerId + "_" + computeResource + "_" + accCardType + "_" + queueCode
if _, has := queueMap[key]; has {
continue
}
var hasInternet = int(models.NoInternet)
if queue.IsNetAccess == models.GrampusNetAccess {
hasInternet = int(models.HasInternet)
}
var queueType = models.QueueTypePublic
if queue.PoolType == models.GrampusPoolTypeExclusive {
queueType = models.QueueTypeExclusive
}
queueMap[key] = ""
queueList = append(queueList, models.GrampusResourceQueue{
QueueCode: queueCode,
QueueName: queue.Name,
QueueType: queueType,
AiCenterCode: centerId,
AiCenterName: c.Name,
ComputeResource: computeResource,
AccCardType: accCardType,
HasInternet: hasInternet,
})
}

}
}
return queueList, nil
}

func GetDebugJobEvents(jobID string) (*models.GetGrampusDebugJobEventsResponse, error) {
checkSetting()
client := getRestyClient()


+ 30
- 5
routers/admin/resources.go View File

@@ -41,18 +41,27 @@ func GetScenePage(ctx *context.Context) {

func GetResourceQueueList(ctx *context.Context) {
page := ctx.QueryInt("page")
pageSize := ctx.QueryInt("pageSize")
cluster := ctx.Query("cluster")
aiCenterCode := ctx.Query("center")
computeResource := ctx.Query("resource")
accCardType := ctx.Query("card")
hasInternet := ctx.QueryInt("hasInternet")
queueType := ctx.Query("queueType")

if pageSize > 1000 {
log.Error("GetResourceQueueList pageSize too large.")
ctx.JSON(http.StatusOK, response.ServerError("pageSize too large"))
return
}
list, err := resource.GetResourceQueueList(models.SearchResourceQueueOptions{
ListOptions: models.ListOptions{Page: page, PageSize: 10},
ListOptions: models.ListOptions{Page: page, PageSize: pageSize},
Cluster: cluster,
AiCenterCode: aiCenterCode,
ComputeResource: computeResource,
AccCardType: accCardType,
HasInternet: models.SpecInternetQuery(hasInternet),
QueueType: queueType,
})
if err != nil {
log.Error("GetResourceQueueList error.%v", err)
@@ -118,6 +127,7 @@ func SyncGrampusQueue(ctx *context.Context) {

func GetResourceSpecificationList(ctx *context.Context) {
page := ctx.QueryInt("page")
pageSize := ctx.QueryInt("pageSize")
queue := ctx.QueryInt64("queue")
status := ctx.QueryInt("status")
cluster := ctx.Query("cluster")
@@ -126,8 +136,14 @@ func GetResourceSpecificationList(ctx *context.Context) {
computeResource := ctx.Query("resource")
cardType := ctx.Query("cardType")
hasInternet := ctx.QueryInt("hasInternet")

if pageSize > 1000 {
log.Error("GetResourceSpecificationList pageSize too large.")
ctx.JSON(http.StatusOK, response.ServerError("pageSize too large"))
return
}
list, err := resource.GetResourceSpecificationList(models.SearchResourceSpecificationOptions{
ListOptions: models.ListOptions{Page: page, PageSize: 10},
ListOptions: models.ListOptions{Page: page, PageSize: pageSize},
QueueId: queue,
Status: status,
Cluster: cluster,
@@ -231,24 +247,33 @@ func SyncGrampusSpecs(ctx *context.Context) {

func GetResourceSceneList(ctx *context.Context) {
page := ctx.QueryInt("page")
pageSize := ctx.QueryInt("pageSize")
jobType := ctx.Query("jobType")
aiCenterCode := ctx.Query("center")
queueId := ctx.QueryInt64("queue")
isExclusive := ctx.QueryInt("IsExclusive")
isExclusive := ctx.Query("isSpecExclusive")
sceneType := ctx.Query("sceneType")
computeResource := ctx.Query("resource")
cardType := ctx.Query("cardType")
cluster := ctx.Query("cluster")
hasInternet := ctx.QueryInt("hasInternet")

if pageSize > 1000 {
log.Error("GetResourceSceneList pageSize too large.")
ctx.JSON(http.StatusOK, response.ServerError("pageSize too large"))
return
}
list, err := resource.GetResourceSceneList(models.SearchResourceSceneOptions{
ListOptions: models.ListOptions{Page: page, PageSize: 10},
ListOptions: models.ListOptions{Page: page, PageSize: pageSize},
JobType: jobType,
IsExclusive: isExclusive,
IsSpecExclusive: isExclusive,
AiCenterCode: aiCenterCode,
QueueId: queueId,
ComputeResource: computeResource,
AccCardType: cardType,
Cluster: cluster,
HasInternet: models.SpecInternetQuery(hasInternet),
SceneType: sceneType,
})
if err != nil {
log.Error("GetResourceSceneList error.%v", err)


+ 100
- 17
services/ai_task_service/cluster/c2net.go View File

@@ -33,7 +33,11 @@ func init() {
}

func (c C2NetClusterAdapter) CreateNoteBook(req entity.CreateNoteBookTaskRequest) (*entity.CreateNoteBookTaskResponse, error) {
jobResult, err := grampus.CreateNotebookJob(convertNoteBookReq2Grampus(req))
newReq, err := convertNoteBookReq2Grampus(req)
if err != nil {
log.Error("CreateNoteBook err.req=%+v err=%v", req, err)
}
jobResult, err := grampus.CreateNotebookJob(newReq)
if err != nil {
log.Error("CreateNoteBook failed: %v", err.Error())
return nil, err
@@ -47,7 +51,12 @@ func (c C2NetClusterAdapter) CreateNoteBook(req entity.CreateNoteBookTaskRequest

func (c C2NetClusterAdapter) CreateOnlineInfer(req entity.CreateNoteBookTaskRequest) (*entity.CreateNoteBookTaskResponse, error) {
log.Info("start to CreateOnlineInfer ")
jobResult, err := grampus.CreateNotebookJob(convertOnlineInfer2Grampus(req))
newReq, err := convertOnlineInfer2Grampus(req)
if err != nil {
log.Error("CreateOnlineInfer err.req=%+v err=%v", req, err)
return nil, err
}
jobResult, err := grampus.CreateNotebookJob(newReq)
if err != nil {
log.Error("CreateNoteBook failed: %v", err.Error())
return nil, err
@@ -109,7 +118,7 @@ func ConvertGrampusImageToStandard(image models.GrampusImage) entity.ClusterImag
}
}

func convertNoteBookReq2Grampus(req entity.CreateNoteBookTaskRequest) models.CreateGrampusNotebookRequest {
func convertNoteBookReq2Grampus(req entity.CreateNoteBookTaskRequest) (models.CreateGrampusNotebookRequest, error) {
codePath := "/code"
if len(req.Tasks[0].Code) > 0 {
codePath = req.Tasks[0].Code[0].ContainerPath
@@ -129,23 +138,31 @@ func convertNoteBookReq2Grampus(req entity.CreateNoteBookTaskRequest) models.Cre
tasks := make([]models.GrampusNotebookTask, len(req.Tasks))
for i := 0; i < len(req.Tasks); i++ {
t := req.Tasks[i]
tasks[i] = convertNoteBookTask2Grampus(t, command)
task, err := convertNoteBookTask2Grampus(t, command)
if err != nil {
return models.CreateGrampusNotebookRequest{}, err
}
tasks[i] = task
}

return models.CreateGrampusNotebookRequest{Name: req.Name, Tasks: tasks}
return models.CreateGrampusNotebookRequest{Name: req.Name, Tasks: tasks}, nil
}

func convertOnlineInfer2Grampus(req entity.CreateNoteBookTaskRequest) models.CreateGrampusNotebookRequest {
func convertOnlineInfer2Grampus(req entity.CreateNoteBookTaskRequest) (models.CreateGrampusNotebookRequest, error) {

command := generateCommand(req.RepoName, req.Tasks[0].BootFile, req.PrimitiveDatasetName)

tasks := make([]models.GrampusNotebookTask, len(req.Tasks))
for i := 0; i < len(req.Tasks); i++ {
t := req.Tasks[i]
tasks[i] = convertNoteBookTask2Grampus(t, command)
task, err := convertNoteBookTask2Grampus(t, command)
if err != nil {
return models.CreateGrampusNotebookRequest{}, nil
}
tasks[i] = task
}

return models.CreateGrampusNotebookRequest{Name: req.Name, Tasks: tasks}
return models.CreateGrampusNotebookRequest{Name: req.Name, Tasks: tasks}, nil
}

func generateCommand(repoName, bootFile, datasetName string) string {
@@ -194,7 +211,7 @@ func getCopyCmd(datasetName, repoName, bootfilepath string) string {
return cmd
}

func convertNoteBookTask2Grampus(t entity.NoteBookTask, command string) models.GrampusNotebookTask {
func convertNoteBookTask2Grampus(t entity.NoteBookTask, command string) (models.GrampusNotebookTask, error) {
code := models.GrampusDataset{}
codeArray := convertContainerArray2GrampusArray(t.Code)
if codeArray != nil && len(codeArray) > 0 {
@@ -205,6 +222,10 @@ func convertNoteBookTask2Grampus(t entity.NoteBookTask, command string) models.G
if outputArray != nil && len(outputArray) > 0 {
output = outputArray[0]
}
centerIds, err := getGrampusAvailableCenterIds(t.Queues, t.ImageId, *models.GetComputeSourceInstance(t.Spec.ComputeResource), models.JobTypeDebug)
if err != nil {
return models.GrampusNotebookTask{}, err
}
return models.GrampusNotebookTask{
Name: t.Name,
ResourceSpecId: t.Spec.SourceSpecId,
@@ -216,8 +237,56 @@ func convertNoteBookTask2Grampus(t entity.NoteBookTask, command string) models.G
AutoStopDuration: t.AutoStopDuration,
Capacity: t.Capacity,
Command: command,
CenterID: t.CenterID,
CenterID: centerIds,
}, nil
}

func getGrampusAvailableCenterIds(queues []models.ResourceQueue, imageId string, computeSource models.ComputeSource, jobType models.JobType) ([]string, error) {
if len(queues) == 0 {
return []string{}, nil
}
var intersectionCenterIds []string
if imageId == "" {
for _, queue := range queues {
code := strings.TrimSuffix(queue.AiCenterCode+"+"+queue.QueueCode, "+")
intersectionCenterIds = append(intersectionCenterIds, code)
}
return intersectionCenterIds, nil
}

processType := computeSource.FullName
images, err := grampus.GetImages(processType, string(jobType))
if err != nil {
log.Warn("can not get image info from grampus", err)
return []string{}, err
}
var imageCenterIds []string
for _, image := range images.Infos {
if image.ID == imageId {
for _, centerInfo := range image.AICenterImage {
imageCenterIds = append(imageCenterIds, centerInfo.AICenterID)
}
break
}
}
if len(imageCenterIds) == 0 {
return []string{}, errors.New("image not available")
}

for _, queue := range queues {
for _, imageCenterId := range imageCenterIds {
if queue.AiCenterCode == imageCenterId {
code := strings.TrimSuffix(queue.AiCenterCode+"+"+queue.QueueCode, "+")
intersectionCenterIds = append(intersectionCenterIds, code)
break
}
}
}
if len(intersectionCenterIds) == 0 {
return intersectionCenterIds, errors.New("no center match")
}

return intersectionCenterIds, nil
}

func convertContainerArray2GrampusArray(containerDatas []entity.ContainerData) []models.GrampusDataset {
@@ -413,7 +482,12 @@ func parseC2NetEventsToOperationProfile(notebookEvents []models.GrampusJobEvents
}

func (c C2NetClusterAdapter) CreateTrainJob(req entity.CreateTrainTaskRequest) (*entity.CreateTrainTaskResponse, error) {
jobResult, err := grampus.CreateJob(convertTrainReq2Grampus(req))
newReq, err := convertTrainReq2Grampus(req)
if err != nil {
log.Error("CreateTrainJob err.req=%+v err=%v", req, err)
return nil, err
}
jobResult, err := grampus.CreateJob(newReq)
if err != nil {
log.Error("CreateNoteBook failed: %v", err.Error())
return nil, err
@@ -421,16 +495,20 @@ func (c C2NetClusterAdapter) CreateTrainJob(req entity.CreateTrainTaskRequest) (
return convertGrampus2TrainRes(jobResult), nil
}

func convertTrainReq2Grampus(req entity.CreateTrainTaskRequest) models.CreateGrampusJobRequest {
func convertTrainReq2Grampus(req entity.CreateTrainTaskRequest) (models.CreateGrampusJobRequest, error) {
command := generateGrampusTrainCommand(req)

tasks := make([]models.GrampusTasks, len(req.Tasks))
for i := 0; i < len(req.Tasks); i++ {
t := req.Tasks[i]
tasks[i] = convertTrainTask2Grampus(t, command)
task, err := convertTrainTask2Grampus(t, command)
if err != nil {
return models.CreateGrampusJobRequest{}, err
}
tasks[i] = task
}

return models.CreateGrampusJobRequest{Name: req.Name, Tasks: tasks}
return models.CreateGrampusJobRequest{Name: req.Name, Tasks: tasks}, nil
}

func generateGrampusTrainCommand(req entity.CreateTrainTaskRequest) string {
@@ -649,7 +727,12 @@ func getNpuModelObjectKey(jobName string) string {
return setting.CodePathPrefix + jobName + RemoteModelPath + "/" + models.ModelSuffix
}

func convertTrainTask2Grampus(t entity.TrainTask, command string) models.GrampusTasks {
func convertTrainTask2Grampus(t entity.TrainTask, command string) (models.GrampusTasks, error) {
centerIds, err := getGrampusAvailableCenterIds(t.Queues, t.ImageId, *models.GetComputeSourceInstance(t.Spec.ComputeResource), models.JobTypeTrain)
if err != nil {
return models.GrampusTasks{}, err
}

return models.GrampusTasks{
Name: t.Name,
ResourceSpecId: t.ResourceSpecId,
@@ -658,13 +741,13 @@ func convertTrainTask2Grampus(t entity.TrainTask, command string) models.Grampus
Datasets: convertContainerArray2GrampusArray(t.Datasets),
Code: convertContainerArray2Grampus(t.Code),
Command: command,
CenterID: t.CenterID,
CenterID: centerIds,
ReplicaNum: 1,
Models: convertContainerArray2GrampusArray(t.PreTrainModel),
BootFile: t.BootFile,
OutPut: convertContainerArray2Grampus(t.OutPut),
WorkServerNumber: t.WorkServerNumber,
}
}, nil
}

func convertGrampus2TrainRes(res *models.CreateGrampusJobResponse) *entity.CreateTrainTaskResponse {


+ 1
- 10
services/ai_task_service/cluster/cloudbrain_two.go View File

@@ -29,9 +29,6 @@ func init() {
}

func (c CloudbrainTwoClusterAdapter) CreateNoteBook(req entity.CreateNoteBookTaskRequest) (*entity.CreateNoteBookTaskResponse, error) {
if poolInfos == nil {
json.Unmarshal([]byte(setting.PoolInfos), &poolInfos)
}
t := req.Tasks[0]

var jobResult *models.CreateNotebookResult
@@ -52,19 +49,13 @@ func (c CloudbrainTwoClusterAdapter) CreateNoteBook(req entity.CreateNoteBookTas
WorkspaceID: "0",
})
} else {
var poolId = poolInfos.PoolInfo[0].PoolId
for _, poolInfo := range poolInfos.PoolInfo {
if poolInfo.PoolName == t.Spec.QueueCode {
poolId = poolInfo.PoolId
}
}
jobResult, err = cloudbrain_two.CreateNotebook2(models.CreateNotebook2Params{
JobName: req.Name,
Description: req.Description,
Flavor: t.Spec.SourceSpecId,
Duration: t.AutoStopDuration,
ImageID: t.ImageId,
PoolID: poolId,
PoolID: t.Spec.QueueCode,
Feature: models.NotebookFeature,
Volume: models.VolumeReq{
Capacity: setting.Capacity,


+ 1
- 0
services/ai_task_service/context/context.go View File

@@ -13,6 +13,7 @@ type CreationContext struct {
GitRepo *git.Repository
Repository *models.Repository
Spec *models.Specification
Queues []models.ResourceQueue
User *models.User
CommitID string
Response *entity.CreationResponse


+ 3
- 11
services/ai_task_service/task/cloudbrain_one_notebook_task.go View File

@@ -90,7 +90,7 @@ func (t CloudbrainOneNotebookTaskTemplate) Create(ctx *context.CreationContext)
Next(t.CheckDatasets).
Next(t.CheckBranchExists).
Next(t.InsertCloudbrainRecord4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.GetAvailableQueues, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
Operate(ctx)
if err != nil {
log.Error("create CloudbrainOneNotebookTask err.%v", err)
@@ -111,6 +111,7 @@ func (t CloudbrainOneNotebookTaskTemplate) Restart(ctx *context.CreationContext)
Next(t.LoadSpec).
Next(t.CheckPointBalance).
Next(t.BuildContainerData).
Next(t.GetAvailableQueues).
Next(t.CallRestartAPI).
Next(t.CreateCloudbrainRecord4Restart).
Next(t.NotifyCreation).
@@ -134,15 +135,6 @@ func (g CloudbrainOneNotebookTaskTemplate) CallCreationAPI(ctx *context.Creation
}
form := ctx.Request

centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}

req := entity.CreateNoteBookTaskRequest{
Name: form.JobName,
Tasks: []entity.NoteBookTask{
@@ -157,7 +149,7 @@ func (g CloudbrainOneNotebookTaskTemplate) CallCreationAPI(ctx *context.Creation
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
AutoStopDuration: autoStopDurationMs,
Capacity: setting.Capacity,
CenterID: centerIds,
Queues: ctx.Queues,
Spec: ctx.Spec,
},
},


+ 2
- 58
services/ai_task_service/task/cloudbrain_one_train_task.go View File

@@ -82,7 +82,7 @@ func (t CloudbrainOneTrainTaskTemplate) Create(ctx *context.CreationContext) (*e
Next(t.CheckDatasets).
Next(t.CheckModel).
Next(t.InsertCloudbrainRecord4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.GetAvailableQueues, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
Operate(ctx)
if err != nil {
log.Error("create GrampusNoteBookTask err.%v", err)
@@ -97,14 +97,6 @@ func (g CloudbrainOneTrainTaskTemplate) CallCreationAPI(ctx *context.CreationCon
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
req := entity.CreateTrainTaskRequest{
Name: form.JobName,
DisplayJobName: form.DisplayJobName,
@@ -116,7 +108,7 @@ func (g CloudbrainOneTrainTaskTemplate) CallCreationAPI(ctx *context.CreationCon
ImageUrl: strings.TrimSpace(form.ImageUrl),
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
CenterID: centerIds,
Queues: ctx.Queues,
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
@@ -139,51 +131,3 @@ func (g CloudbrainOneTrainTaskTemplate) CallCreationAPI(ctx *context.CreationCon
}
return nil
}

func (g CloudbrainOneTrainTaskTemplate) CallRestartAPI(ctx *context.CreationContext) *response.BizError {
c := g.GetMyCluster()
if c == nil {
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
req := entity.CreateTrainTaskRequest{
Name: form.JobName,
DisplayJobName: form.DisplayJobName,
Tasks: []entity.TrainTask{
{
Name: form.JobName,
ResourceSpecId: ctx.Spec.SourceSpecId,
ImageId: form.ImageID,
ImageUrl: strings.TrimSpace(form.ImageUrl),
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
CenterID: centerIds,
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
Params: form.ParamArray,
Spec: ctx.Spec,
},
},
}
createTime := timeutil.TimeStampNow()
res, err := c.CreateTrainJob(req)
if err != nil {
log.Error("CloudbrainOneTrainTaskTemplate CallRestartAPI err.req=%+v err=%v", req, err)
return response.NewBizError(err)
}
ctx.Response = &entity.CreationResponse{
JobID: res.JobID,
Status: res.Status,
CreateTime: createTime,
}
return nil
}

+ 3
- 28
services/ai_task_service/task/cloudbrain_two_train_task.go View File

@@ -1,14 +1,11 @@
package task

import (
"encoding/json"
"strings"

"code.gitea.io/gitea/entity"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/routers/response"
"code.gitea.io/gitea/services/ai_task_service/context"
@@ -86,7 +83,7 @@ func (t CloudbrainTwoTrainTaskTemplate) Create(ctx *context.CreationContext) (*e
Next(t.CheckDatasets).
Next(t.CheckModel).
Next(t.InsertCloudbrainRecord4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.GetAvailableQueues, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
Operate(ctx)
if err != nil {
log.Error("create GrampusNoteBookTask err.%v", err)
@@ -100,29 +97,7 @@ func (g CloudbrainTwoTrainTaskTemplate) CallCreationAPI(ctx *context.CreationCon
if c == nil {
return response.SYSTEM_ERROR
}
var resourcePools modelarts.ResourcePool
if err := json.Unmarshal([]byte(setting.ResourcePools), &resourcePools); err != nil {
log.Error("Unmarshal error. %v", err)
return response.NewBizError(err)
} else if len(resourcePools.Info) == 0 {
log.Error("UresourcePools.Info is empty. %v", err)
return response.SYSTEM_ERROR
}
modelarts_poolid := resourcePools.Info[0].ID
for _, t := range resourcePools.Info {
if t.Value == ctx.Spec.QueueCode {
modelarts_poolid = t.ID
}
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
req := entity.CreateTrainTaskRequest{
Name: form.JobName,
DisplayJobName: form.DisplayJobName,
@@ -136,13 +111,13 @@ func (g CloudbrainTwoTrainTaskTemplate) CallCreationAPI(ctx *context.CreationCon
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
LogPath: ctx.GetContainerDataArray(entity.ContainerLogPath),
CenterID: centerIds,
Queues: ctx.Queues,
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
Params: form.ParamArray,
Spec: ctx.Spec,
PoolId: modelarts_poolid,
PoolId: ctx.Spec.QueueCode,
WorkServerNumber: form.WorkServerNumber,
},
},


+ 2
- 10
services/ai_task_service/task/grampus_notebook_task.go View File

@@ -156,7 +156,7 @@ func (t GrampusNoteBookTaskTemplate) Create(ctx *context.CreationContext) (*enti
Next(t.CheckBranchExists).
Next(t.CheckModel).
Next(t.InsertCloudbrainRecord4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.GetAvailableQueues, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
Operate(ctx)
if err != nil {
log.Error("create GrampusNoteBookTask err.%v", err)
@@ -199,14 +199,6 @@ func (g GrampusNoteBookTaskTemplate) CallCreationAPI(ctx *context.CreationContex
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
imageUrl := strings.TrimSpace(form.ImageUrl)
if form.ImageID != "" {
imageUrl = ""
@@ -223,7 +215,7 @@ func (g GrampusNoteBookTaskTemplate) CallCreationAPI(ctx *context.CreationContex
Code: ctx.GetContainerDataArray(entity.ContainerCode),
AutoStopDuration: autoStopDurationMs,
Capacity: setting.Capacity,
CenterID: centerIds,
Queues: ctx.Queues,
Spec: ctx.Spec,
},
},


+ 2
- 10
services/ai_task_service/task/grampus_online_infer_task.go View File

@@ -80,7 +80,7 @@ func (t GrampusOnlineInferTaskTemplate) Create(ctx *context.CreationContext) (*e
Next(t.CheckBranchExists).
Next(t.CheckModel).
Next(t.InsertCloudbrainRecord4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.GetAvailableQueues, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
Operate(ctx)
if err != nil {
log.Error("create GrampusNoteBookTask err.%v", err)
@@ -97,14 +97,6 @@ func (g GrampusOnlineInferTaskTemplate) CallCreationAPI(ctx *context.CreationCon
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
imageUrl := strings.TrimSpace(form.ImageUrl)
if form.ImageID != "" {
imageUrl = ""
@@ -129,7 +121,7 @@ func (g GrampusOnlineInferTaskTemplate) CallCreationAPI(ctx *context.CreationCon
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
AutoStopDuration: -1,
Capacity: setting.Capacity,
CenterID: centerIds,
Queues: ctx.Queues,
Spec: ctx.Spec,
BootFile: ctx.Request.BootFile,
},


+ 2
- 58
services/ai_task_service/task/grampus_train_task.go View File

@@ -116,7 +116,7 @@ func (t GrampusTrainTaskTemplate) Create(ctx *context.CreationContext) (*entity.
Next(t.CheckDatasets).
Next(t.CheckModel).
Next(t.InsertCloudbrainRecord4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.GetAvailableQueues, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
Operate(ctx)
if err != nil {
log.Error("create GrampusTrainTaskTemplate err.%v", err)
@@ -131,14 +131,6 @@ func (g GrampusTrainTaskTemplate) CallCreationAPI(ctx *context.CreationContext)
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
imageUrl := strings.TrimSpace(form.ImageUrl)
if form.ImageID != "" {
imageUrl = ""
@@ -154,7 +146,7 @@ func (g GrampusTrainTaskTemplate) CallCreationAPI(ctx *context.CreationContext)
ImageUrl: imageUrl,
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
CenterID: centerIds,
Queues: ctx.Queues,
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
@@ -179,51 +171,3 @@ func (g GrampusTrainTaskTemplate) CallCreationAPI(ctx *context.CreationContext)
}
return nil
}

func (g GrampusTrainTaskTemplate) CallRestartAPI(ctx *context.CreationContext) *response.BizError {
c := g.GetMyCluster()
if c == nil {
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
req := entity.CreateTrainTaskRequest{
Name: form.JobName,
DisplayJobName: form.DisplayJobName,
Tasks: []entity.TrainTask{
{
Name: form.JobName,
ResourceSpecId: ctx.Spec.SourceSpecId,
ImageId: form.ImageID,
ImageUrl: strings.TrimSpace(form.ImageUrl),
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
CenterID: centerIds,
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
Params: form.ParamArray,
Spec: ctx.Spec,
},
},
}
createTime := timeutil.TimeStampNow()
res, err := c.CreateTrainJob(req)
if err != nil {
log.Error("GrampusTrainTaskTemplate CallRestartAPI err.req=%+v err=%v", req, err)
return response.NewBizError(err)
}
ctx.Response = &entity.CreationResponse{
JobID: res.JobID,
Status: res.Status,
CreateTime: createTime,
}
return nil
}

+ 10
- 0
services/ai_task_service/task/opt_handler.go View File

@@ -43,6 +43,7 @@ type CreationHandler interface {
NotifyCreation(ctx *context.CreationContext) *response.BizError
HandleErr4Async(ctx *context.CreationContext) *response.BizError
CheckNotebookCount(ctx *context.CreationContext) *response.BizError
GetAvailableQueues(ctx *context.CreationContext) *response.BizError
}

//DefaultCreationHandler CreationHandler的默认实现,公共逻辑可以在此结构体中实现
@@ -633,6 +634,15 @@ func (DefaultCreationHandler) CheckPointBalance(ctx *context.CreationContext) *r
return nil
}

func (DefaultCreationHandler) GetAvailableQueues(ctx *context.CreationContext) *response.BizError {
ctx.Queues = ctx.Spec.GetAvailableQueues(models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: ctx.Request.JobType,
HasInternet: ctx.Request.HasInternet,
})
return nil
}

func (DefaultCreationHandler) CallCreationAPI(ctx *context.CreationContext) *response.BizError {
log.Error("CallCreationAPI not implements")
return response.SYSTEM_ERROR


+ 9
- 2
services/ai_task_service/task/task_extend.go View File

@@ -139,6 +139,12 @@ func getCloudBrainDatasetInfo4Local(uuid string, datasetname string, isNeedDown

//根据实际调度的智算中心修正规格
func correctAITaskSpec(task *models.Cloudbrain) {
defer func() {
if err := recover(); err != nil {
combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2))
log.Error("PANIC:%v", combinedErr)
}
}()
if task.AiCenter == "" {
return
}
@@ -161,13 +167,14 @@ func correctAITaskSpec(task *models.Cloudbrain) {
log.Error("correctAITaskSpec GetCloudbrainSpecByID spec is empty.taskId=%d ", task.ID)
return
}
if oldSpec.AiCenterCode == realCenterCode {
if oldSpec.AiCenterCode == realCenterCode && oldSpec.QueueCode == task.QueueCode {
return
}
//智算中心不一样时才需要处理
//所属资源池队列不一样时才需要处理
r, err := models.FindSpecs(models.FindSpecsOptions{
SourceSpecId: oldSpec.SourceSpecId,
AiCenterCode: realCenterCode,
QueueCode: task.QueueCode,
})
if err != nil {
log.Error("correctAITaskSpec FindSpecs err.taskId=%d err=%v", task.ID, err)


+ 1
- 44
services/ai_task_service/task/task_service.go View File

@@ -11,7 +11,6 @@ import (
"strings"

"code.gitea.io/gitea/entity"
"code.gitea.io/gitea/manager/client/grampus"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/git"
@@ -260,6 +259,7 @@ func UpdateByQueryResponse(res *entity.QueryTaskResponse, task *models.Cloudbrai
if res.CenterId != "" && res.CenterName != "" {
task.AiCenter = res.CenterId + "+" + res.CenterName
}
task.QueueCode = res.QueueCode
oldStatus := task.Status
newStatus := TransAITaskStatus(res.Status)

@@ -733,49 +733,6 @@ func SyncAITaskStatus() {
}
}
}
func GetAvailableCenterIds(specification *models.Specification, opts models.GetAvailableCenterIdOpts, computeSource *models.ComputeSource,
imageId string, clusterType entity.ClusterType) ([]string, *response.BizError) {
centerIds := specification.GetAvailableCenterIds(opts)

if len(centerIds) == 0 || imageId == "" || clusterType != entity.C2Net {
return centerIds, nil
}

processType := computeSource.FullName
images, err := grampus.GetImages(processType, string(opts.JobType))
if err != nil {
log.Warn("can not get image info from grampus", err)
return centerIds, nil
}
var imageCenterIds []string
for _, image := range images.Infos {
if image.ID == imageId {
for _, centerInfo := range image.AICenterImage {
imageCenterIds = append(imageCenterIds, centerInfo.AICenterID)
}
break
}
}
if len(imageCenterIds) == 0 {
return centerIds, nil
}

var intersectionCenterIds []string
for _, centerId := range centerIds {
for _, imageCenterId := range imageCenterIds {
if centerId == imageCenterId {
intersectionCenterIds = append(intersectionCenterIds, centerId)
break
}
}
}
if len(intersectionCenterIds) == 0 {
return intersectionCenterIds, response.NO_CENTER_MATCH
}

return intersectionCenterIds, nil

}

func HandleNoJobIdAITasks() {
defer func() {


+ 43
- 47
services/cloudbrain/resource/resource_queue.go View File

@@ -5,7 +5,6 @@ import (
"code.gitea.io/gitea/modules/grampus"
"code.gitea.io/gitea/modules/log"
"fmt"
"strings"
)

func AddResourceQueue(req models.ResourceQueueReq) error {
@@ -18,6 +17,8 @@ func AddResourceQueue(req models.ResourceQueueReq) error {
func UpdateResourceQueue(queueId int64, req models.ResourceQueueReq) error {
if _, err := models.UpdateResourceCardsTotalNumAndInternetStatus(queueId, models.ResourceQueue{
CardsTotalNum: req.CardsTotalNum,
QueueType: req.QueueType,
QueueName: req.QueueName,
Remark: req.Remark,
HasInternet: req.HasInternet,
}); err != nil {
@@ -54,8 +55,9 @@ func GetResourceAiCenters() ([]models.ResourceAiCenterRes, error) {
}

func SyncGrampusQueue(doerId int64) error {
r, err := grampus.GetAiCenters(1, 100)
r, err := grampus.GetResourceQueue()
if err != nil {
log.Error("Get grampus resource queue failed.err=%v", err)
return err
}
log.Info("SyncGrampusQueue result = %+v", r)
@@ -63,56 +65,50 @@ func SyncGrampusQueue(doerId int64) error {
queueInsertList := make([]models.ResourceQueue, 0)
existIds := make([]int64, 0)

for _, center := range r.Infos {
for _, device := range center.AccDevices {
computeResource := models.ParseComputeResourceFormGrampus(device.Kind)
accCardType := strings.ToUpper(device.Model)
if computeResource == "" {
continue
}
//Determine if this quque already exists.if exist,update params
//if not exist,insert a new record
oldQueue, err := models.GetResourceQueue(&models.ResourceQueue{
for _, queue := range r {
computeResource := queue.ComputeResource
accCardType := queue.AccCardType
oldQueue, err := models.GetResourceQueue(&models.ResourceQueue{
Cluster: models.C2NetCluster,
AiCenterCode: queue.AiCenterCode,
ComputeResource: computeResource,
AccCardType: accCardType,
QueueCode: queue.QueueCode,
})
if err != nil {
return err
}

hasInternet := queue.HasInternet
if oldQueue == nil {
queueInsertList = append(queueInsertList, models.ResourceQueue{
Cluster: models.C2NetCluster,
AiCenterCode: center.Id,
AiCenterCode: queue.AiCenterCode,
AiCenterName: queue.AiCenterName,
ComputeResource: computeResource,
AccCardType: accCardType,
IsAutomaticSync: true,
HasInternet: hasInternet,
CreatedBy: doerId,
UpdatedBy: doerId,
QueueCode: queue.QueueCode,
QueueName: queue.QueueName,
QueueType: queue.QueueType,
})
} else {
existIds = append(existIds, oldQueue.ID)
queueUpdateList = append(queueUpdateList, models.ResourceQueue{
ID: oldQueue.ID,
ComputeResource: computeResource,
AiCenterName: queue.AiCenterName,
AccCardType: accCardType,
UpdatedBy: doerId,
HasInternet: hasInternet,
QueueName: queue.QueueName,
QueueType: queue.QueueType,
})
if err != nil {
return err
}

var hasInternet int
if center.IsNetAccess {
hasInternet = 2
} else {
hasInternet = 1
}
if oldQueue == nil {
queueInsertList = append(queueInsertList, models.ResourceQueue{
Cluster: models.C2NetCluster,
AiCenterCode: center.Id,
AiCenterName: center.Name,
ComputeResource: computeResource,
AccCardType: accCardType,
IsAutomaticSync: true,
HasInternet: hasInternet,
CreatedBy: doerId,
UpdatedBy: doerId,
})
} else {
existIds = append(existIds, oldQueue.ID)
queueUpdateList = append(queueUpdateList, models.ResourceQueue{
ID: oldQueue.ID,
ComputeResource: computeResource,
AiCenterName: center.Name,
AccCardType: accCardType,
UpdatedBy: doerId,
HasInternet: hasInternet,
})
}

}

}
return models.SyncGrampusQueues(queueUpdateList, queueInsertList, existIds)
}


+ 1
- 0
services/cloudbrain/resource/resource_scene.go View File

@@ -5,6 +5,7 @@ import (
)

func AddResourceScene(req models.ResourceSceneReq) error {

if err := models.InsertResourceScene(req); err != nil {
return err
}


+ 8
- 0
services/cloudbrain/resource/resource_specification.go View File

@@ -255,6 +255,14 @@ func AddSpecOperateLog(doerId int64, operateType string, newValue, oldValue *mod

func FindAvailableSpecs(userId int64, opts models.FindSpecsOptions) ([]*models.Specification, error) {
opts.SpecStatus = models.SpecOnShelf

isUserSpecial := models.IsUserInExclusivePool(userId)
if isUserSpecial {
opts.SceneType = models.SceneTypeExclusive
} else {
opts.SceneType = models.SceneTypePublic
}

r, err := models.FindSpecs(opts)
if err != nil {
log.Error("FindAvailableSpecs error.%v", err)


+ 1
- 1
templates/admin/navbar.tmpl View File

@@ -1,5 +1,5 @@
<div class="ui secondary pointing tabular top attached borderless menu stackable new-menu navbar" style="margin-top:0">
<div class="item-container">
<div class="item-container" style="position:sticky;top:0;">
<a class="{{if .PageIsAdminDashboard}}active{{end}} item" href="{{AppSubUrl}}/admin">
{{.i18n.Tr "admin.dashboard"}}
</a>


+ 3
- 0
templates/computingpower/domestic.tmpl View File

@@ -1,5 +1,8 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-computingpower-domestic.css?v={{MD5 AppVer}}"/>
{{if .IsOperator}}
<script>window.IS_OPERATOR = true;</script>
{{end}}
<div>
<div id="__vue-root"></div>
</div>


+ 5
- 3
web_src/vuepages/apis/modules/resources.js View File

@@ -142,7 +142,8 @@ export const syncResSpecification = () => {
{
"SceneName":"启智集群调试任务", //应用场景名
"JobType":"TRAIN", //任务类型 DEBUG调试任务 BENCHMARK 评测任务 TRAIN 训练 INFERENCE 推理
"IsExclusive":true, //是否专属
"sceneType":"public",
"IsSpecExclusive":true, //是否专属
"ExclusiveOrg":"123,456", //专属组织
"SpecIds":[2,3] // 资源规格id
}
@@ -160,7 +161,7 @@ export const addResScene = (data) => {
// params: action:edit-编辑 delete-删除,
// data: {
// "SceneName":"启智集群调试任务", //应用场景名
// "IsExclusive":true, //是否专属
// "IsSpecExclusive":true, //是否专属
// "ExclusiveOrg":"123,456", //专属组织
// "SpecIds":[2,3] // 资源规格id
//}
@@ -180,7 +181,8 @@ export const updateResScene = (data) => {
// jobType
// center
// queue 所属队列
// IsExclusive 是否专属 1 专属 2 非专属
// sceneType
// IsSpecExclusive 是否专属 1 专属 2 非专属
// cardType 卡类型
// resource 计算资源
export const getResSceneList = (params) => {


+ 17
- 10
web_src/vuepages/langs/config/en-US.js View File

@@ -138,7 +138,10 @@ const en = {
addResQueue: 'Add Resources Queue',
addResQueueBtn: 'Add Resources Queue',
editResQueue: 'Edit Resources Queue',
resQueueCode: 'Resources Queue Code',
resQueueName: 'Resources Queue Name',
resQueueType: "Resources Queue Type",
allResQueueType: "All Resources Queue Type",
whichCluster: 'Cluster',
allCluster: 'All Clusters',
aiCenter: 'AI Center',
@@ -183,10 +186,14 @@ const en = {
resSceneName: 'Resources Scene Name',
jobType: 'Job Type',
allJobType: 'All Job Type',
isExclusive: 'Is Exclusive?',
allExclusiveAndCommonUse: 'All Exclusive and Common Use',
exclusive: 'Exclusive',
commonUse: 'Common Use',
sceneType: "Community Scene Type",
allSceneType: "All Community Scene Type",
isExclusiveSpec: 'Is Exclusive Spec?',
allExclusiveAndCommonUseSpec: 'All Exclusive and Common Use Spec',
public: "Public",
exclusive: "Exclusive",
exclusiveSpec: 'Exclusive Spec',
commonUseSpec: 'Common Use Spec',
exclusiveOrg: 'Exclusive Organization',
exclusiveOrgTips: 'Multiple organization names are separated by semicolons',
computeCluster: 'Compute Cluster',
@@ -365,7 +372,7 @@ const en = {
forkModelSuccess: 'The model content has been copied and forked successfully!',
debugModel: 'Debug Model',
onlineInference: 'online Inference',
deleted:'Deleted',
deleted: 'Deleted',
},
repos: {
activeOrganization: 'Active Organization',
@@ -621,7 +628,7 @@ const en = {
maxTaskTips: '<p><span>*</span>The platform only retains the results of debug, train, inference and evaluation tasks for nearly<span> 30 </span> days. <span>Tasks over 30 days will not be able to download results and view logs, and cannot be debugged or trained again</span></p>',
datasetFiles: 'Dataset files',
fileWasDeleted: 'The file has been deleted',
debugTaskEmptyTitle: 'Debug task has not been created',
debugTaskEmptyTitle: 'Debug task has not been created',
debugTaskEmptyTip0: 'Code version: You have not initialized the code repository, please <a href="{url}">initialized</a> first;',
debugTaskEmptyTip1: 'Running time: no more than 4 hours, it will automatically stop if it exceeds 4 hours;',
debugTaskEmptyTip2: 'Dataset: Cloud Brain 1 provides CPU/GPU,Cloud Brain 2 provides Ascend NPU.And dataset also needs to be uploaded to the corresponding environment;',
@@ -693,7 +700,7 @@ const en = {
modelSquare: {
llmHeader: 'Document dialogue experience',
chatGlm_intro: 'is an open source conversational language model that supports Chinese and English bilingualism, provided by Zhipu AI.',
llama2:'is a collection of pretrained and fine-tuned generative text models ranging in scale from 7 billion to 70 billion parameters. This is the repository for the 7B fine-tuned model, optimized for dialogue use cases and converted for the Hugging Face Transformers format.',
llama2: 'is a collection of pretrained and fine-tuned generative text models ranging in scale from 7 billion to 70 billion parameters. This is the repository for the 7B fine-tuned model, optimized for dialogue use cases and converted for the Hugging Face Transformers format.',
dialogtips1: 'Hello 👋! Welcome to experience the large model knowledge base Q&A',
dialogtips21: 'This experience is based on',
dialogtips22: 'language model and m3-base vector model',
@@ -715,7 +722,7 @@ const en = {
deleteVbTips: 'Are you sure to delete the knowledge base files?',
uploadFile: 'Upload files',
uploadFileTips1: 'Drag the file here, or click <em>to upload</em>',
uploadFileTips2:'Single file upload size limit is 1MB • HTML, MD, JSON, CSV, TXT, XML, DOCX',
uploadFileTips2: 'Single file upload size limit is 1MB • HTML, MD, JSON, CSV, TXT, XML, DOCX',
addFileToKb: 'Add files to the knowledge base',
manageFile: 'Manage files',
deleteKbFileSelect: 'Please select the file to delete from the existing files in the knowledge base',
@@ -725,8 +732,8 @@ const en = {
fileExit: 'File already exists',
fileExceed: 'Files exceeding 1MB',
fileError: 'File error, please re-upload!',
fileTypeError:'File type error, please re-upload!',
fileUploadSuccess:'{fileName} File uploaded successfully!',
fileTypeError: 'File type error, please re-upload!',
fileUploadSuccess: '{fileName} File uploaded successfully!',
kbName: 'Knowledge Base Name',
createKbPlaceholder: 'The new knowledge base name can only be numbers and letters',
vectorType: 'Vector Library Type',


+ 14
- 7
web_src/vuepages/langs/config/zh-CN.js View File

@@ -137,7 +137,10 @@ const zh = {
addResQueue: "新建资源池(队列)",
addResQueueBtn: "新增资源池",
editResQueue: "修改资源池(队列)",
resQueueCode: "资源池(队列)编码",
resQueueName: "资源池(队列)名称",
resQueueType: "资源池(队列)类型",
allResQueueType: "全部资源池(队列)类型",
whichCluster: "所属集群",
allCluster: "全部集群",
aiCenter: "智算中心",
@@ -182,10 +185,14 @@ const zh = {
resSceneName: "应用场景名称",
jobType: "任务类型",
allJobType: "全部任务类型",
isExclusive: "是否专属",
allExclusiveAndCommonUse: "全部专属和通用",
exclusive: "专属",
commonUse: "通用",
sceneType: "社区资源性质",
allSceneType: "全部社区资源性质",
isExclusiveSpec: "是否专属资源规格",
allExclusiveAndCommonUseSpec: "全部专属和通用资源规格",
public: "共享(public)",
exclusive: "独占(exclusive)",
exclusiveSpec: "专属资源规格",
commonUseSpec: "通用资源规格",
exclusiveOrg: "专属组织",
exclusiveOrgTips: "多个组织名之间用英文分号隔开",
computeCluster: "算力集群",
@@ -695,7 +702,7 @@ const zh = {
tips4: '以下为平台固定需要的代码 替换gradio的demo.launch()启动方式',
tips5: '因为在线推理目前没有代码运行错误的消息提示反馈,代码需要在调试环境下先确定原先gradio代码运行没有错误,确保代码能跑起来,不然在线推理会直接呈现succeeded或failed状态。',
tips61: '详细使用方法可查看',
tips62:'使用样例代码仓',
tips62: '使用样例代码仓',
tips7: '不再提示',
tips8: '关闭',
tips9: 'OpenI在线推理部署须知',
@@ -742,7 +749,7 @@ const zh = {
fileExit: '文件已经存在',
fileExceed: '文件超过1MB',
fileError: '文件错误,请重新上传!',
fileTypeError:'文类型件错误,请重新上传!',
fileTypeError: '文类型件错误,请重新上传!',
fileUploadSuccess: '{fileName}文件上传成功!',
kbName: '知识库名称',
createKbPlaceholder: '新知识库名称只能是数字和字母',
@@ -757,7 +764,7 @@ const zh = {
useNotice: '使用体验须知',
agreeNotice: '同意 <a href="/home/model_privacy" target="_blank"> 《OpenI启智社区AI协作平台免责声明和服务使用规范》 </a>中所述内容 <p style="text-align: center;margin-top: 1rem;color: red;">温馨提示:不合理使用可能会被封号!</p>',
modelProvide: '<a href="/home/model_privacy" target="_blank">《免责声明和服务使用规范》</a>本模型体验由<a href="https://ai.blsc.cn/" target="_blank"> 北京超级云计算中心 </a>提供算力支持',
maxTries: '限量体验{maxTries}次',
modelChatTask: '创建模型在线体验任务',
createChatTips1: '单击下方按钮创建在线体验任务,创建成功后可在线体验{expireMinutes}分钟',


+ 3
- 0
web_src/vuepages/pages/computingpower/domestic/index.vue View File

@@ -122,6 +122,7 @@ const manufacturerIconMap = {
export default {
data() {
return {
isOperator: false,
loading: false,
useSmall: false,
tabList: [
@@ -435,6 +436,8 @@ export default {
},
},
created() {
this.isOperator = window.IS_OPERATOR;
if (!this.isOperator) this.sortList.splice(1, 1);
this.getData();
},
mounted() {


+ 23
- 1
web_src/vuepages/pages/resources/components/QueueDialog.vue View File

@@ -7,13 +7,32 @@
<div class="form">
<div class="form-row">
<div class="title required">
<span>{{ $t('resourcesManagement.resQueueName') }}</span>
<span>{{ $t('resourcesManagement.resQueueCode') }}</span>
</div>
<div class="content">
<el-input v-model="dataInfo.QueueCode" placeholder="" :disabled="type === 'edit'" maxlength="255">
</el-input>
</div>
</div>
<div class="form-row">
<div class="title">
<span>{{ $t('resourcesManagement.resQueueName') }}</span>
</div>
<div class="content">
<el-input v-model="dataInfo.QueueName" placeholder="" maxlength="255">
</el-input>
</div>
</div>
<div class="form-row">
<div class="title">
<span>{{ $t('resourcesManagement.resQueueType') }}</span>
</div>
<div class="content">
<el-select v-model="dataInfo.QueueType" clearable>
<el-option v-for="item in queueTypeList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
</div>
</div>
<div class="form-row">
<div class="title required">
<span>{{ $t('resourcesManagement.whichCluster') }}</span>
@@ -111,6 +130,7 @@ export default {
data() {
return {
dialogShow: false,
queueTypeList: [{ k: 'public', v: 'public' }, { k: 'exclusive', v: 'exclusive' }],
clusterList: [CLUSTERS[0]],
computingCenterList: [AI_CENTER[0], AI_CENTER[1], AI_CENTER[2]],
computingTypeList: [...COMPUTER_RESOURCES],
@@ -129,6 +149,8 @@ export default {
this.dataInfo = {
ID: '',
QueueCode: '',
QueueName: '',
QueueType: '',
Cluster: '',
AiCenterCode: '',
ComputeResource: '',


+ 33
- 13
web_src/vuepages/pages/resources/components/SceneDialog.vue View File

@@ -25,15 +25,25 @@
</div>
<div class="form-row">
<div class="title required">
<span>{{ $t('resourcesManagement.isExclusive') }}</span>
<span>{{ $t('resourcesManagement.sceneType') }}</span>
</div>
<div class="content">
<el-select v-model="dataInfo.IsExclusive" @change="changeIsExclusive">
<el-option v-for="item in isExclusiveList" :key="item.k" :label="item.v" :value="item.k" />
<el-select v-model="dataInfo.SceneType" @change="changeSceneType">
<el-option v-for="item in sceneTypeList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
</div>
</div>
<div class="form-row" v-if="dataInfo.IsExclusive === '1'">
<div class="form-row" v-if="dataInfo.SceneType == 'public'">
<div class="title required">
<span>{{ $t('resourcesManagement.isExclusiveSpec') }}</span>
</div>
<div class="content">
<el-select v-model="dataInfo.IsSpecExclusive" @change="changeIsSpecExclusive">
<el-option v-for="item in isSpecExclusiveList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
</div>
</div>
<div class="form-row" v-if="dataInfo.IsSpecExclusive === 'exclusive' || dataInfo.SceneType == 'exclusive'">
<div class="title required">
<span>{{ $t('resourcesManagement.exclusiveOrg') }}</span>
</div>
@@ -100,7 +110,8 @@ export default {
clusterList: [...CLUSTERS],
accCardTypeList: [...ACC_CARD_TYPE],
statusList: [...SPECIFICATION_STATUS],
isExclusiveList: [{ k: '2', v: this.$t('resourcesManagement.commonUse') }, { k: '1', v: this.$t('resourcesManagement.exclusive') }],
sceneTypeList: [{ k: 'public', v: this.$t('resourcesManagement.public') }, { k: 'exclusive', v: this.$t('resourcesManagement.exclusive') }],
isSpecExclusiveList: [{ k: 'public', v: this.$t('resourcesManagement.commonUseSpec') }, { k: 'exclusive', v: this.$t('resourcesManagement.exclusiveSpec') }],
resourceList: [...COMPUTER_RESOURCES],
networkTypeList: [...NETWORK_TYPE_VALUE],
specsList: [],
@@ -116,7 +127,8 @@ export default {
this.dataInfo = {
SceneName: '',
JobType: '',
IsExclusive: '2',
SceneType: '',
IsSpecExclusive: '',
ExclusiveOrg: '',
Cluster: 'OpenI',
Resource: 'GPU',
@@ -130,8 +142,6 @@ export default {
resource: this.dataInfo.Resource,
queue: this.dataInfo.QueueId === '-1' ? '' : this.dataInfo.QueueId,
available: 1,
// status: 2,
// page: 1,
};
return getResSpecificationListAll(params).then(res => {
res = res.data;
@@ -140,10 +150,12 @@ export default {
const data = list.map((item) => {
const NGPU = `${item.ComputeResource}:${item.AccCardsNum + '*' + getListValueWithKey(this.accCardTypeList, item.AccCardType)}`;
const statusStr = item.Status != '2' ? `<span style="color:rgb(245, 34, 45)">(${getListValueWithKey(this.statusList, item.Status.toString())})</span>` : '';
const queueName = item.QueueName ? `【${item.QueueName}】` : '';
const queueType = item.QueueType ? `【${item.QueueType}】` : '';
return {
...item,
StatusStr: statusStr,
QueueStr: `${item.QueueCode}(${getListValueWithKey(this.clusterList, item.Cluster)} - ${item.AiCenterName})`,
QueueStr: `${item.QueueCode}${queueName}${queueType}(${getListValueWithKey(this.clusterList, item.Cluster)} - ${item.AiCenterName})`,
SpecStr: `${NGPU}, CPU:${item.CpuCores}, ${this.$t('resourcesManagement.gpuMem')}:${item.GPUMemGiB}GB, ${this.$t('resourcesManagement.mem')}:${item.MemGiB}GB, ${this.$t('resourcesManagement.shareMem')}:${item.ShareMemGiB}GB`,
PriceStr: `, ${this.$t('resourcesManagement.unitPrice')}:${item.UnitPrice}${this.$t('resourcesManagement.point_hr')}`,
NetworkTypeStr: `, ${this.$t('cloudbrainObj.networkType')}:${getListValueWithKey(this.networkTypeList, item.HasInternet)}`,
@@ -155,7 +167,11 @@ export default {
console.log(err);
});
},
changeIsExclusive() {
changeSceneType() {
this.dataInfo.IsSpecExclusive = '';
this.changeIsSpecExclusive();
},
changeIsSpecExclusive() {
this.dataInfo.ExclusiveOrg = '';
},
changeCluster() {
@@ -177,7 +193,8 @@ export default {
ID: this.data.ID,
SceneName: this.data.SceneName,
JobType: this.data.JobType,
IsExclusive: this.data.IsExclusive,
SceneType: this.data.SceneType,
IsSpecExclusive: this.data.IsSpecExclusive,
ExclusiveOrg: this.data.ExclusiveOrg,
Cluster: this.data.Cluster,
Resource: this.data.ComputeResource,
@@ -198,7 +215,10 @@ export default {
this.$emit("update:visible", false);
},
confirm() {
if (!this.dataInfo.SceneName || !this.dataInfo.JobType || !this.dataInfo.SpecIds.length || (this.dataInfo.IsExclusive === '1' && !this.dataInfo.ExclusiveOrg)) {
if (!this.dataInfo.SceneName || !this.dataInfo.JobType || !this.dataInfo.SceneType || !this.dataInfo.SpecIds.length
|| (this.dataInfo.IsSpecExclusive === 'exclusive' && !this.dataInfo.ExclusiveOrg)
|| (this.dataInfo.SceneType === 'exclusive' && !this.dataInfo.ExclusiveOrg)
) {
this.$message({
type: 'info',
message: this.$t('pleaseCompleteTheInformationFirst')
@@ -211,7 +231,7 @@ export default {
setApi({
...this.dataInfo,
action: this.type === 'edit' ? 'edit' : undefined,
IsExclusive: this.dataInfo.IsExclusive === '1',
IsSpecExclusive: this.dataInfo.IsSpecExclusive,
}).then(res => {
res = res.data;
if (res.Code === 0) {


+ 24
- 12
web_src/vuepages/pages/resources/components/SpecSelect.vue View File

@@ -23,23 +23,23 @@
<div v-if="tabIndex == '1'">
<div>
<div class="header row">
<div class="row-l" style="width:600px;">{{ $t('resourcesManagement.resourceSpecification') }}</div>
<div class="row-l" style="width:480px;">{{ $t('resourcesManagement.resourceSpecification') }}</div>
<div class="row-r" style="flex:1">{{ $t('resourcesManagement.resQueue') }}</div>
</div>
<div class="table-content">
<div class="row" v-for="(item, index) in tableData1" :key="index">
<div class="row-l" style="width:600px;">{{ item.SpecStr }}</div>
<div class="row-l" style="width:480px;">{{ item.SpecStr }}</div>
<div class="row-r" style="flex:1">
<div class="btn-c">
<button @click="selectAll(item.queues)">{{ $t('selectAll') }}</button>
<button @click="clearSelectAll(item.queues)">{{ $t('selectNone') }}</button>
</div>
<div class="" v-for="_item in item.queues" :key="_item.ID">
<div class="row-item" v-for="_item in item.queues" :key="_item.ID">
<el-checkbox :value="_item.checked" @change="selectChange(_item.ID)">
<span
v-html="_item.QueueStr + _item.PriceStr + _item.NetworkTypeStr + _item.StatusStr"></span>
</el-checkbox>
</div>
<div class="btn-c">
<button @click="selectAll(item.queues)">{{ $t('selectAll') }}</button>
<button @click="clearSelectAll(item.queues)">{{ $t('selectNone') }}</button>
</div>
</div>
</div>
</div>
@@ -54,15 +54,15 @@
<div class="row" v-for="(item, index) in tableData2" :key="index">
<div class="row-l" style="width:400px;">{{ item.QueueStr }}</div>
<div class="row-r" style="flex:1">
<div class="btn-c">
<button @click="selectAll(item.specs)">{{ $t('selectAll') }}</button>
<button @click="clearSelectAll(item.specs)">{{ $t('selectNone') }}</button>
</div>
<div class="" v-for="_item in item.specs" :key="_item.ID">
<div class="row-item" v-for="_item in item.specs" :key="_item.ID">
<el-checkbox :value="_item.checked" @change="selectChange(_item.ID)">
<span v-html="_item.SpecStr + _item.PriceStr + _item.NetworkTypeStr + _item.StatusStr"></span>
</el-checkbox>
</div>
<div class="btn-c">
<button @click="selectAll(item.specs)">{{ $t('selectAll') }}</button>
<button @click="clearSelectAll(item.specs)">{{ $t('selectNone') }}</button>
</div>
</div>
</div>
</div>
@@ -534,6 +534,18 @@ export default {
}
}
}

.row-item {
&:first-child {
margin-right: 80px;
}

/deep/ .el-checkbox {
white-space: break-spaces;
display: inline-flex;
align-items: center;
}
}
}

&:last-child {


+ 3
- 1
web_src/vuepages/pages/resources/components/SpecificationDialog.vue View File

@@ -169,9 +169,11 @@ export default {
const list = [];
for (let i = 0, iLen = data.length; i < iLen; i++) {
const item = data[i];
const queueName = item.QueueName ? `【${item.QueueName}】` : '';
const queueType = item.QueueType ? `【${item.QueueType}】` : '';
list.push({
k: item.ID,
v: `${item.QueueCode}(${getListValueWithKey(this.clusterList, item.Cluster)} - ${item.AiCenterName})`,
v: `${item.QueueCode}${queueName}${queueType}(${getListValueWithKey(this.clusterList, item.Cluster)} - ${item.AiCenterName})`,
});
}
this.queueList.splice(0, Infinity, ...list);


+ 26
- 8
web_src/vuepages/pages/resources/queue/index.vue View File

@@ -6,13 +6,16 @@
<el-select class="select" size="medium" v-model="selCluster" @change="selectChange">
<el-option v-for="item in clusterList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selComputingCenter" @change="selectChange">
<el-select class="select" size="medium" v-model="selQueueType" @change="selectChange">
<el-option v-for="item in queueTypeList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" filterable v-model="selComputingCenter" @change="selectChange">
<el-option v-for="item in computingCenterList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selComputingType" @change="selectChange">
<el-select class="select" size="medium" filterable v-model="selComputingType" @change="selectChange">
<el-option v-for="item in computingTypeList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selCardType" @change="selectChange">
<el-select class="select" size="medium" filterable v-model="selCardType" @change="selectChange">
<el-option v-for="item in cardTypeList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selNetworkType" @change="selectChange">
@@ -31,7 +34,15 @@
<el-table border :data="tableData" style="width: 100%" v-loading="loading" stripe>
<el-table-column prop="ID" label="ID" align="center" header-align="center" width="80"></el-table-column>
<el-table-column prop="QueueCode" :label="$t('resourcesManagement.resQueueName')" align="center"
header-align="center"></el-table-column>
header-align="center">
<template slot-scope="scope">
<span :title="scope.row.Cluster">{{ `${scope.row.QueueCode}${scope.row.QueueName ?
'【' + scope.row.QueueName + '】' : ''}` }}</span>
</template>
</el-table-column>
<el-table-column prop="QueueType" :label="$t('resourcesManagement.resQueueType')" align="center"
header-align="center" width="130">
</el-table-column>
<el-table-column prop="ClusterName" :label="$t('resourcesManagement.whichCluster')" align="center"
header-align="center">
<template slot-scope="scope">
@@ -76,8 +87,8 @@
<div class="__r_p_pagination">
<div style="margin-top: 2rem">
<div class="center">
<el-pagination background @current-change="currentChange" :current-page="pageInfo.curpage"
:page-sizes="pageInfo.pageSizes" :page-size="pageInfo.pageSize"
<el-pagination background @current-change="currentChange" @size-change="pageSizeChange"
:current-page="pageInfo.curpage" :page-sizes="pageInfo.pageSizes" :page-size="pageInfo.pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="pageInfo.total">
</el-pagination>
</div>
@@ -101,6 +112,8 @@ export default {
return {
selCluster: '',
clusterList: [{ k: '', v: this.$t('resourcesManagement.allCluster') }, ...CLUSTERS],
selQueueType: '',
queueTypeList: [{ k: '', v: this.$t('resourcesManagement.allResQueueType') }, { k: 'public', v: 'public' }, { k: 'exclusive', v: 'exclusive' }],
selComputingCenter: '',
computingCenterList: [{ k: '', v: this.$t('resourcesManagement.allAiCenter') }],
selComputingType: '',
@@ -115,7 +128,7 @@ export default {
pageInfo: {
curpage: 1,
pageSize: 10,
pageSizes: [10],
pageSizes: [10, 50, 100],
total: 0,
},
queueDialogShow: false,
@@ -145,12 +158,13 @@ export default {
getTableData() {
const params = {
cluster: this.selCluster,
queueType: this.selQueueType,
center: this.selComputingCenter,
resource: this.selComputingType,
card: this.selCardType,
hasInternet: this.selNetworkType,
page: this.pageInfo.curpage,
pagesize: this.pageInfo.pageSize,
pageSize: this.pageInfo.pageSize,
};
this.loading = true;
getResQueueList(params).then(res => {
@@ -212,6 +226,10 @@ export default {
this.pageInfo.curpage = val;
this.getTableData();
},
pageSizeChange(val) {
this.pageInfo.pageSize = val;
this.getTableData();
},
showDialog(type, data) {
this.queueDialogType = type;
this.queueDialogData = data ? { ...data } : {};


+ 52
- 20
web_src/vuepages/pages/resources/scene/index.vue View File

@@ -6,8 +6,11 @@
<el-select class="select" size="medium" v-model="selTaskType" @change="selectChange">
<el-option v-for="item in taskTypeList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selIsExclusive" @change="selectChange">
<el-option v-for="item in isExclusiveList" :key="item.k" :label="item.v" :value="item.k" />
<el-select class="select" size="medium" v-model="selSceneType" @change="selectChange">
<el-option v-for="item in sceneTypeList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selIsSpecExclusive" @change="selectChange">
<el-option v-for="item in IsSpecExclusiveList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selCluster" @change="selectChange">
<el-option v-for="item in clusterList" :key="item.k" :label="item.v" :value="item.k" />
@@ -42,16 +45,26 @@
<el-table-column prop="JobTypeStr" :label="$t('resourcesManagement.jobType')" align="center"
header-align="center" width="120">
</el-table-column>
<el-table-column prop="IsExclusiveStr" :label="$t('resourcesManagement.isExclusive')" align="center"
<el-table-column prop="SceneTypeStr" :label="$t('resourcesManagement.sceneType')" align="center"
header-align="center" width="120">
<template slot-scope="scope">
<span :style="{ color: scope.row.IsExclusive ? 'red' : '' }">{{ scope.row.IsExclusiveStr }}</span>
<span :style="{ color: scope.row.SceneType == 'exclusive' ? 'red' : '' }">
{{ scope.row.SceneTypeStr }}
</span>
</template>
</el-table-column>
<el-table-column prop="IsSpecExclusiveStr" :label="$t('resourcesManagement.isExclusiveSpec')" align="center"
header-align="center" width="120">
<template slot-scope="scope">
<span :style="{ color: scope.row.IsSpecExclusive == 'exclusive' ? 'red' : '' }">
{{ scope.row.IsSpecExclusiveStr }}
</span>
</template>
</el-table-column>
<el-table-column prop="ExclusiveOrg" :label="$t('resourcesManagement.exclusiveOrg')" align="center"
header-align="center">
<template slot-scope="scope">
<span>{{ scope.row.IsExclusive ? scope.row.ExclusiveOrg : '--' }}</span>
<span>{{ scope.row.ExclusiveOrg ? scope.row.ExclusiveOrg : '--' }}</span>
</template>
</el-table-column>
<el-table-column prop="specStr" :label="$t('resourcesManagement.resourceSpecification')" align="left"
@@ -69,8 +82,8 @@
</div>
</template>
</el-table-column>
<el-table-column prop="QueueStr" :label="$t('resourcesManagement.resQueue')" align="center"
header-align="center" width="350">
<el-table-column prop="QueueStr" :label="$t('resourcesManagement.resQueue')" align="left" header-align="center"
width="350">
<template slot-scope="scope">
<div v-if="!scope.row.queues.length">--</div>
<div v-for=" item in scope.row.queues " :key="item.key">
@@ -94,8 +107,8 @@
<div class="__r_p_pagination">
<div style="margin-top: 2rem">
<div class="center">
<el-pagination background @current-change="currentChange" :current-page="pageInfo.curpage"
:page-sizes="pageInfo.pageSizes" :page-size="pageInfo.pageSize"
<el-pagination background @current-change="currentChange" @size-change="pageSizeChange"
:current-page="pageInfo.curpage" :page-sizes="pageInfo.pageSizes" :page-size="pageInfo.pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="pageInfo.total">
</el-pagination>
</div>
@@ -118,8 +131,10 @@ export default {
return {
selTaskType: '',
taskTypeList: [{ k: '', v: this.$t('resourcesManagement.allJobType') }, ...JOB_TYPE],
selIsExclusive: '',
isExclusiveList: [{ k: '', v: this.$t('resourcesManagement.allExclusiveAndCommonUse') }, { k: '1', v: this.$t('resourcesManagement.exclusive') }, { k: '2', v: this.$t('resourcesManagement.commonUse') }],
selIsSpecExclusive: '',
IsSpecExclusiveList: [{ k: '', v: this.$t('resourcesManagement.allExclusiveAndCommonUseSpec') }, { k: 'exclusive', v: this.$t('resourcesManagement.exclusiveSpec') }, { k: 'public', v: this.$t('resourcesManagement.commonUseSpec') }],
selSceneType: '',
sceneTypeList: [{ k: '', v: this.$t('resourcesManagement.allSceneType') }, { k: 'public', v: this.$t('resourcesManagement.public') }, { k: 'exclusive', v: this.$t('resourcesManagement.exclusive') }],
selQueue: '',
queueList: [{ k: '', v: this.$t('resourcesManagement.allResQueue') }],
selCluster: '',
@@ -139,7 +154,7 @@ export default {
pageInfo: {
curpage: 1,
pageSize: 10,
pageSizes: [10],
pageSizes: [10, 50, 100],
total: 0,
},
sceneDialogShow: false,
@@ -150,7 +165,7 @@ export default {
components: { SceneDialog },
methods: {
tableSpanMethod({ row, column, rowIndex, columnIndex }) {
if ([0, 1, 2, 3, 4, 8].indexOf(columnIndex) > -1) {
if ([0, 1, 2, 3, 4, 5, 9].indexOf(columnIndex) > -1) {
if (row.rowspan) {
return {
rowspan: row.rowspan,
@@ -189,9 +204,11 @@ export default {
const list = [];
for (let i = 0, iLen = data.length; i < iLen; i++) {
const item = data[i];
const queueName = item.QueueName ? `【${item.QueueName}】` : '';
const queueType = item.QueueType ? `【${item.QueueType}】` : '';
list.push({
k: item.ID,
v: `${item.QueueCode}(${getListValueWithKey(this.clusterList, item.Cluster)} - ${item.AiCenterName}) ${item.ComputeResource}(${item.AccCardType})`,
v: `${item.QueueCode}${queueName}${queueType}(${getListValueWithKey(this.clusterList, item.Cluster)} - ${item.AiCenterName}) ${item.ComputeResource}(${item.AccCardType})`,
});
}
this.queueList.push(...list);
@@ -203,7 +220,8 @@ export default {
getTableData() {
const params = {
jobType: this.selTaskType,
IsExclusive: this.selIsExclusive,
sceneType: this.selSceneType,
isSpecExclusive: this.selIsSpecExclusive,
cluster: this.selCluster,
queue: this.selQueue,
center: this.selAiCenter,
@@ -211,7 +229,7 @@ export default {
cardType: this.selCardType,
hasInternet: this.selNetworkType,
page: this.pageInfo.curpage,
pagesize: this.pageInfo.pageSize,
pageSize: this.pageInfo.pageSize,
};
this.loading = true;
getResSceneList(params).then(res => {
@@ -230,7 +248,8 @@ export default {
const statusStr = spec.Status != '2' ? `<span style="color:rgb(245, 34, 45)">(${getListValueWithKey(this.statusList, spec.Status.toString())})</span>` : '';
spec.specStr = `${NGPU}, CPU:${spec.CpuCores}, ${this.$t('resourcesManagement.gpuMem')}:${spec.GPUMemGiB}GB, ${this.$t('resourcesManagement.mem')}:${spec.MemGiB}GB, ${this.$t('resourcesManagement.shareMem')}:${spec.ShareMemGiB}GB`;
spec.JobTypeStr = getListValueWithKey(this.taskTypeList, item.JobType);
spec.IsExclusiveStr = getListValueWithKey(this.isExclusiveList, item.IsExclusive ? '1' : '2');
spec.SceneTypeStr = getListValueWithKey(this.sceneTypeList.slice(1, Infinity), item.SceneType);
spec.IsSpecExclusiveStr = item.SceneType == 'exclusive' ? '--' : getListValueWithKey(this.IsSpecExclusiveList.slice(1, Infinity), item.IsSpecExclusive);
spec.statusStr = statusStr;
spec.priceStr = `, ${this.$t('resourcesManagement.unitPrice')}:${spec.UnitPrice}${this.$t('resourcesManagement.point_hr')}`
spec.networkTypeStr = `, ${this.$t('cloudbrainObj.networkType')}:${getListValueWithKey(NETWORK_TYPE_VALUE, spec.HasInternet)}`
@@ -249,12 +268,16 @@ export default {
const queues = [];
for (let k = 0, kLen = _specs.length; k < kLen; k++) {
const _spec = _specs[k];
const queueName = _spec.QueueName ? `【${_spec.QueueName}】` : '';
const queueType = _spec.QueueType ? `【${_spec.QueueType}】` : '';
queues.push({
QueueId: _spec.QueueId,
QueueCode: _spec.QueueCode,
QueueName: _spec.QueueName,
QueueType: _spec.QueueType,
AiCenterCode: _spec.AiCenterCode,
AiCenterName: _spec.AiCenterName,
QueueStr: `${_spec.QueueCode}(${getListValueWithKey(this.clusterList, _spec.Cluster)} - ${_spec.AiCenterName})`,
QueueStr: `${_spec.QueueCode}${queueName}${queueType}(${getListValueWithKey(this.clusterList, _spec.Cluster)} - ${_spec.AiCenterName})`,
statusStr: _spec.statusStr,
priceStr: _spec.priceStr,
networkTypeStr: _spec.networkTypeStr,
@@ -265,14 +288,18 @@ export default {
} else {
for (let k = 0, kLen = _specs.length; k < kLen; k++) {
const _spec = _specs[k];
const queueName = _spec.QueueName ? `【${_spec.QueueName}】` : '';
const queueType = _spec.QueueType ? `【${_spec.QueueType}】` : '';
data.push({
..._spec,
queues: [{
QueueId: _spec.QueueId,
QueueCode: _spec.QueueCode,
QueueName: _spec.QueueName,
QueueType: _spec.QueueType,
AiCenterCode: _spec.AiCenterCode,
AiCenterName: _spec.AiCenterName,
QueueStr: `${_spec.QueueCode}(${getListValueWithKey(this.clusterList, _spec.Cluster)} - ${_spec.AiCenterName})`,
QueueStr: `${_spec.QueueCode}${queueName}${queueType}(${getListValueWithKey(this.clusterList, _spec.Cluster)} - ${_spec.AiCenterName})`,
statusStr: _spec.statusStr,
priceStr: _spec.priceStr,
networkTypeStr: _spec.networkTypeStr,
@@ -316,6 +343,10 @@ export default {
this.pageInfo.curpage = val;
this.getTableData();
},
pageSizeChange(val) {
this.pageInfo.pageSize = val;
this.getTableData();
},
deleteRow(row) {
this.$confirm(this.$t('resourcesManagement.resSceneDeleteConfirm'), this.$t('tips'), {
confirmButtonText: this.$t('confirm1'),
@@ -354,7 +385,8 @@ export default {
ID: data._id_,
SceneName: data.SceneName,
JobType: data.JobType,
IsExclusive: data.IsExclusive ? '1' : '2',
SceneType: data.SceneType,
IsSpecExclusive: data.IsSpecExclusive,
ExclusiveOrg: data.ExclusiveOrg,
Cluster: data.Cluster,
ComputeResource: data.ComputeResource,


+ 18
- 11
web_src/vuepages/pages/resources/specification/index.vue View File

@@ -3,7 +3,7 @@
<div class="title"><span>{{ $t('resourcesManagement.resSpecificationAndPriceManagement') }}</span></div>
<div class="tools-bar">
<div>
<el-select class="select" size="medium" v-model="selQueue" @change="selectChange">
<el-select class="select" size="medium" filterable v-model="selQueue" @change="selectChange">
<el-option v-for="item in queueList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selStatus" @change="selectChange">
@@ -12,10 +12,10 @@
<el-select class="select" size="medium" v-model="selAvailable" @change="selectChange">
<el-option v-for="item in availableList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selResource" @change="selectChange">
<el-select class="select" size="medium" filterable v-model="selResource" @change="selectChange">
<el-option v-for="item in resourceList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selCardType" @change="selectChange">
<el-select class="select" size="medium" filterable v-model="selCardType" @change="selectChange">
<el-option v-for="item in cardTypeList" :key="item.k" :label="item.v" :value="item.k" />
</el-select>
<el-select class="select" size="medium" v-model="selCardsNum" @change="selectChange">
@@ -39,7 +39,7 @@
<el-table-column prop="SpecStr" :label="$t('resourcesManagement.resourceSpecification')" align="left" fixed
header-align="center" min-width="200">
</el-table-column>
<el-table-column prop="QueueInfo" :label="$t('resourcesManagement.resQueue')" align="center" fixed
<el-table-column prop="QueueInfo" :label="$t('resourcesManagement.resQueue')" align="left" fixed
header-align="center" min-width="100">
</el-table-column>
<el-table-column prop="SourceSpecId" :label="$t('resourcesManagement.sourceSpecCode')" align="center"
@@ -118,8 +118,8 @@
<div class="__r_p_pagination">
<div style="margin-top: 2rem">
<div class="center">
<el-pagination background @current-change="currentChange" :current-page="pageInfo.curpage"
:page-sizes="pageInfo.pageSizes" :page-size="pageInfo.pageSize"
<el-pagination background @current-change="currentChange" @size-change="pageSizeChange"
:current-page="pageInfo.curpage" :page-sizes="pageInfo.pageSizes" :page-size="pageInfo.pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="pageInfo.total">
</el-pagination>
</div>
@@ -181,7 +181,7 @@ export default {
pageInfo: {
curpage: 1,
pageSize: 10,
pageSizes: [10],
pageSizes: [10, 50, 100],
total: 0,
},
specificationDialogShow: false,
@@ -204,9 +204,11 @@ export default {
const list = [];
for (let i = 0, iLen = data.length; i < iLen; i++) {
const item = data[i];
const queueName = item.QueueName ? `【${item.QueueName}】` : '';
const queueType = item.QueueType ? `【${item.QueueType}】` : '';
list.push({
k: item.ID,
v: `${item.QueueCode}(${getListValueWithKey(this.clusterList, item.Cluster)} - ${item.AiCenterName}) ${item.ComputeResource}(${item.AccCardType})`,
v: `${item.QueueCode}${queueName}${queueType}(${getListValueWithKey(this.clusterList, item.Cluster)} - ${item.AiCenterName}) ${item.ComputeResource}(${item.AccCardType})`,
});
}
this.queueList.push(...list);
@@ -225,7 +227,7 @@ export default {
cardsNum: this.selCardsNum,
hasInternet: this.selNetworkType,
page: this.pageInfo.curpage,
pagesize: this.pageInfo.pageSize,
pageSize: this.pageInfo.pageSize,
};
this.loading = true;
getResSpecificationList(params).then(res => {
@@ -236,14 +238,15 @@ export default {
const data = list.map((item) => {
const Queue = item.Queue;
const Spec = item.Spec;
// const NGPU = `${Queue.ComputeResource}:${Spec.AccCardsNum === 0 ? '0' : Spec.AccCardsNum + '*' + getListValueWithKey(this.accCardTypeList, Queue.AccCardType)}`;
const NGPU = `${Queue.ComputeResource}:${Spec.AccCardsNum + '*' + getListValueWithKey(this.accCardTypeList, Queue.AccCardType)}`;
const queueName = Queue.QueueName ? `【${Queue.QueueName}】` : '';
const queueType = Queue.QueueType ? `【${Queue.QueueType}】` : '';
return {
...Spec,
SourceSpecId: Spec.SourceSpecId || '--',
SpecStr: `${NGPU}, CPU:${Spec.CpuCores}, ${this.$t('resourcesManagement.gpuMem')}:${Spec.GPUMemGiB}GB, ${this.$t('resourcesManagement.mem')}:${Spec.MemGiB}GB, ${this.$t('resourcesManagement.shareMem')}:${Spec.ShareMemGiB}GB`,
QueueId: Queue.ID,
QueueInfo: `${Queue.QueueCode}(${getListValueWithKey(this.clusterList, Queue.Cluster)} - ${Queue.AiCenterName})`,
QueueInfo: `${Queue.QueueCode}${queueName}${queueType}(${getListValueWithKey(this.clusterList, Queue.Cluster)} - ${Queue.AiCenterName})`,
UpdatedTimeStr: formatDate(new Date(Spec.UpdatedTime * 1000), 'yyyy-MM-dd HH:mm:ss'),
Status: Spec.Status.toString(),
StatusStr: getListValueWithKey(this.statusList, Spec.Status.toString()),
@@ -294,6 +297,10 @@ export default {
this.pageInfo.curpage = val;
this.getTableData();
},
pageSizeChange(val) {
this.pageInfo.pageSize = val;
this.getTableData();
},
showDialog(type, data, editOr) {
this.specificationDialogType = type;
this.specificationDialogEditOr = !!editOr;


Loading…
Cancel
Save