Browse Source

Merge pull request '接入成都智算中心的notebook' (#2853) from cd-notebook into V20220908

Reviewed-on: https://git.openi.org.cn/OpenI/aiforge/pulls/2853
Reviewed-by: ychao_1983 <ychao_1983@sina.com>
tags/v1.22.9.1^2
ychao_1983 3 years ago
parent
commit
01afc35e8b
12 changed files with 869 additions and 184 deletions
  1. +23
    -36
      models/cloudbrain.go
  2. +2
    -2
      modules/grampus/grampus.go
  3. +9
    -9
      modules/modelarts/modelarts.go
  4. +214
    -0
      modules/modelarts_cd/modelarts.go
  5. +220
    -0
      modules/modelarts_cd/resty.go
  6. +42
    -0
      modules/modelarts_gateway/core/escape.go
  7. +208
    -0
      modules/modelarts_gateway/core/signer.go
  8. +73
    -7
      modules/setting/setting.go
  9. +1
    -0
      options/locale/locale_en-US.ini
  10. +1
    -0
      options/locale/locale_zh-CN.ini
  11. +5
    -3
      routers/repo/cloudbrain.go
  12. +71
    -127
      routers/repo/modelarts.go

+ 23
- 36
models/cloudbrain.go View File

@@ -25,7 +25,8 @@ type ModelArtsJobStatus string
const ( const (
TypeCloudBrainOne int = iota TypeCloudBrainOne int = iota
TypeCloudBrainTwo TypeCloudBrainTwo
TypeC2Net //智算网络
TypeC2Net //智算网络
TypeCDCenter //成都智算中心


TypeCloudBrainAll = -1 TypeCloudBrainAll = -1
) )
@@ -596,37 +597,17 @@ type ResourceSpec struct {
ShareMemMiB int `json:"shareMemMiB"` ShareMemMiB int `json:"shareMemMiB"`
} }


type FlavorInfos struct {
FlavorInfo []*FlavorInfo `json:"flavor_info"`
}

type FlavorInfo struct {
Id int `json:"id"`
Value string `json:"value"`
Desc string `json:"desc"`
}

type SpecialPools struct { type SpecialPools struct {
Pools []*SpecialPool `json:"pools"` Pools []*SpecialPool `json:"pools"`
} }
type SpecialPool struct { type SpecialPool struct {
Org string `json:"org"`
Type string `json:"type"`
IsExclusive bool `json:"isExclusive"`
Pool []*GpuInfo `json:"pool"`
JobType []string `json:"jobType"`
ResourceSpec []*ResourceSpec `json:"resourceSpecs"`
Flavor []*FlavorInfo `json:"flavor"`
}

type ImageInfosModelArts struct {
ImageInfo []*ImageInfoModelArts `json:"image_info"`
}

type ImageInfoModelArts struct {
Id string `json:"id"`
Value string `json:"value"`
Desc string `json:"desc"`
Org string `json:"org"`
Type string `json:"type"`
IsExclusive bool `json:"isExclusive"`
Pool []*GpuInfo `json:"pool"`
JobType []string `json:"jobType"`
ResourceSpec []*ResourceSpec `json:"resourceSpecs"`
Flavor []*setting.FlavorInfo `json:"flavor"`
} }


type PoolInfos struct { type PoolInfos struct {
@@ -732,6 +713,17 @@ type CreateNotebook2Params struct {
Volume VolumeReq `json:"volume"` Volume VolumeReq `json:"volume"`
} }


type CreateNotebookWithoutPoolParams struct {
JobName string `json:"name"`
Description string `json:"description"`
Duration int64 `json:"duration"` //ms
Feature string `json:"feature"`
Flavor string `json:"flavor"`
ImageID string `json:"image_id"`
WorkspaceID string `json:"workspace_id"`
Volume VolumeReq `json:"volume"`
}

type VolumeReq struct { type VolumeReq struct {
Capacity int `json:"capacity"` Capacity int `json:"capacity"`
Category string `json:"category"` Category string `json:"category"`
@@ -955,6 +947,7 @@ type NotebookGetJobTokenResult struct {
} }


type NotebookDelResult struct { type NotebookDelResult struct {
NotebookResult
InstanceID string `json:"instance_id"` InstanceID string `json:"instance_id"`
} }


@@ -1481,12 +1474,6 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
) )
} }


if len(opts.ComputeResource) > 0 {
cond = cond.And(
builder.Eq{"cloudbrain.compute_resource": opts.ComputeResource},
)
}

if len(opts.JobTypes) > 0 { if len(opts.JobTypes) > 0 {
if opts.JobTypeNot { if opts.JobTypeNot {
cond = cond.And( cond = cond.And(
@@ -1506,7 +1493,7 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
if (opts.Cluster) != "" { if (opts.Cluster) != "" {
if opts.Cluster == "resource_cluster_openi" { if opts.Cluster == "resource_cluster_openi" {
cond = cond.And( cond = cond.And(
builder.Or(builder.Eq{"cloudbrain.type": TypeCloudBrainOne}, builder.Eq{"cloudbrain.type": TypeCloudBrainTwo}),
builder.Or(builder.Eq{"cloudbrain.type": TypeCloudBrainOne}, builder.Eq{"cloudbrain.type": TypeCloudBrainTwo}, builder.Eq{"cloudbrain.type": TypeCDCenter}),
) )
} }
if opts.Cluster == "resource_cluster_c2net" { if opts.Cluster == "resource_cluster_c2net" {
@@ -1959,7 +1946,7 @@ func GetWaitingCloudbrainCount(cloudbrainType int, computeResource string, jobTy


func GetCloudbrainNotebookCountByUserID(userID int64) (int, error) { func GetCloudbrainNotebookCountByUserID(userID int64) (int, error) {
count, err := x.In("status", ModelArtsCreateQueue, ModelArtsCreating, ModelArtsStarting, ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsRestarting). count, err := x.In("status", ModelArtsCreateQueue, ModelArtsCreating, ModelArtsStarting, ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsRestarting).
And("job_type = ? and user_id = ? and type = ?", JobTypeDebug, userID, TypeCloudBrainTwo).Count(new(Cloudbrain))
And("job_type = ? and user_id = ? and type in (?,?)", JobTypeDebug, userID, TypeCloudBrainTwo, TypeCDCenter).Count(new(Cloudbrain))
return int(count), err return int(count), err
} }




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

@@ -30,8 +30,8 @@ const (


var ( var (
poolInfos *models.PoolInfos poolInfos *models.PoolInfos
FlavorInfos *models.FlavorInfos
ImageInfos *models.ImageInfosModelArts
FlavorInfos *setting.StFlavorInfos
ImageInfos *setting.StImageInfosModelArts


SpecialPools *models.SpecialPools SpecialPools *models.SpecialPools
) )


+ 9
- 9
modules/modelarts/modelarts.go View File

@@ -1,6 +1,7 @@
package modelarts package modelarts


import ( import (
"code.gitea.io/gitea/modules/modelarts_cd"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@@ -68,8 +69,6 @@ const (


var ( var (
poolInfos *models.PoolInfos poolInfos *models.PoolInfos
FlavorInfos *models.FlavorInfos
ImageInfos *models.ImageInfosModelArts
TrainFlavorInfos *Flavor TrainFlavorInfos *Flavor
SpecialPools *models.SpecialPools SpecialPools *models.SpecialPools
MultiNodeConfig *MultiNodes MultiNodeConfig *MultiNodes
@@ -757,11 +756,7 @@ func GetNotebookImageName(imageId string) (string, error) {
var validImage = false var validImage = false
var imageName = "" var imageName = ""


if ImageInfos == nil {
json.Unmarshal([]byte(setting.ImageInfos), &ImageInfos)
}

for _, imageInfo := range ImageInfos.ImageInfo {
for _, imageInfo := range setting.StImageInfos.ImageInfo {
if imageInfo.Id == imageId { if imageInfo.Id == imageId {
validImage = true validImage = true
imageName = imageInfo.Value imageName = imageInfo.Value
@@ -825,8 +820,13 @@ func HandleTrainJobInfo(task *models.Cloudbrain) error {
} }


func HandleNotebookInfo(task *models.Cloudbrain) error { func HandleNotebookInfo(task *models.Cloudbrain) error {

result, err := GetNotebook2(task.JobID)
var result *models.GetNotebook2Result
var err error
if task.Type == models.TypeCloudBrainTwo {
result, err = GetNotebook2(task.JobID)
} else if task.Type == models.TypeCDCenter {
result, err = modelarts_cd.GetNotebook(task.JobID)
}
if err != nil { if err != nil {
log.Error("GetNotebook2(%s) failed:%v", task.DisplayJobName, err) log.Error("GetNotebook2(%s) failed:%v", task.DisplayJobName, err)
return err return err


+ 214
- 0
modules/modelarts_cd/modelarts.go View File

@@ -0,0 +1,214 @@
package modelarts_cd

import (
"errors"
"strconv"
"strings"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
)

const (
//notebook
storageTypeOBS = "obs"
autoStopDuration = 4 * 60 * 60
autoStopDurationMs = 4 * 60 * 60 * 1000
MORDELART_USER_IMAGE_ENGINE_ID = -1
DataSetMountPath = "/home/ma-user/work"
NotebookEnv = "Python3"
NotebookType = "Ascend"
FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)"

//train-job
CodePath = "/code/"
OutputPath = "/output/"
ResultPath = "/result/"
LogPath = "/log/"
JobPath = "/job/"
OrderDesc = "desc" //向下查询
OrderAsc = "asc" //向上查询
Lines = 500
TrainUrl = "train_url"
DataUrl = "data_url"
MultiDataUrl = "multi_data_url"
ResultUrl = "result_url"
CkptUrl = "ckpt_url"
DeviceTarget = "device_target"
Ascend = "Ascend"
PerPage = 10
IsLatestVersion = "1"
NotLatestVersion = "0"
VersionCountOne = 1

SortByCreateTime = "create_time"
ConfigTypeCustom = "custom"
TotalVersionCount = 1
)

var ()

type VersionInfo struct {
Version []struct {
ID int `json:"id"`
Value string `json:"value"`
Url string `json:"url"`
} `json:"version"`
}

type Flavor struct {
Info []struct {
Code string `json:"code"`
Value string `json:"value"`
} `json:"flavor"`
}

type Engine struct {
Info []struct {
ID int `json:"id"`
Value string `json:"value"`
} `json:"engine"`
}

type ResourcePool struct {
Info []struct {
ID string `json:"id"`
Value string `json:"value"`
} `json:"resource_pool"`
}

type Parameters struct {
Parameter []struct {
Label string `json:"label"`
Value string `json:"value"`
} `json:"parameter"`
}

func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, description, flavor, imageId string) error {
imageName, err := GetNotebookImageName(imageId)
if err != nil {
log.Error("GetNotebookImageName failed: %v", err.Error())
return err
}
createTime := timeutil.TimeStampNow()
jobResult, err := createNotebook(models.CreateNotebookWithoutPoolParams{
JobName: jobName,
Description: description,
Flavor: flavor,
Duration: autoStopDurationMs,
ImageID: imageId,
Feature: models.NotebookFeature,
Volume: models.VolumeReq{
Capacity: setting.Capacity,
Category: models.EVSCategory,
Ownership: models.ManagedOwnership,
},
WorkspaceID: "0",
})
if err != nil {
log.Error("createNotebook failed: %v", err.Error())
if strings.HasPrefix(err.Error(), UnknownErrorPrefix) {
log.Info("(%s)unknown error, set temp status", displayJobName)
errTemp := models.InsertCloudbrainTemp(&models.CloudbrainTemp{
JobID: models.TempJobId,
VersionID: models.TempVersionId,
Status: models.TempJobStatus,
Type: models.TypeCDCenter,
JobName: jobName,
JobType: string(models.JobTypeDebug),
})
if errTemp != nil {
log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error())
return errTemp
}
}
return err
}
task := &models.Cloudbrain{
Status: jobResult.Status,
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobResult.ID,
JobName: jobName,
FlavorCode: flavor,
DisplayJobName: displayJobName,
JobType: string(models.JobTypeDebug),
Type: models.TypeCDCenter,
Uuid: uuid,
ComputeResource: models.NPUResource,
Image: imageName,
Description: description,
CreatedUnix: createTime,
UpdatedUnix: createTime,
}

err = models.CreateCloudbrain(task)
if err != nil {
return err
}

stringId := strconv.FormatInt(task.ID, 10)
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask)
return nil
}

func GetNotebookImageName(imageId string) (string, error) {
var validImage = false
var imageName = ""

for _, imageInfo := range setting.StImageInfos.ImageInfo {
if imageInfo.Id == imageId {
validImage = true
imageName = imageInfo.Value
}
}

if !validImage {
log.Error("the image id(%s) is invalid", imageId)
return imageName, errors.New("the image id is invalid")
}

return imageName, nil
}

/*
func HandleNotebookInfo(task *models.Cloudbrain) error {

result, err := GetNotebook(task.JobID)
if err != nil {
log.Error("GetNotebook2(%s) failed:%v", task.DisplayJobName, err)
return err
}

if result != nil {
oldStatus := task.Status
task.Status = result.Status
if task.StartTime == 0 && result.Lease.UpdateTime > 0 {
task.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000)
}
if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) {
task.EndTime = timeutil.TimeStampNow()
}
task.CorrectCreateUnix()
task.ComputeAndSetDuration()
if oldStatus != task.Status {
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
}
if task.FlavorCode == "" {
task.FlavorCode = result.Flavor
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err)
return err
}
}

return nil
}

*/

+ 220
- 0
modules/modelarts_cd/resty.go View File

@@ -0,0 +1,220 @@
package modelarts_cd

import (
"bytes"
"code.gitea.io/gitea/modules/modelarts_gateway/core"
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"time"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)

var (
httpClient *http.Client
HOST string
TOKEN string
)

const (
errorCodeExceedLimit = "ModelArts.0118"

//notebook 2.0
urlNotebook2 = "/notebooks"

//error code
modelartsIllegalToken = "ModelArts.6401"
NotebookNotFound = "ModelArts.6404"
NotebookNoPermission = "ModelArts.6407"
NotebookInvalid = "ModelArts.6400"
UnknownErrorPrefix = "UNKNOWN:"
)

func getHttpClient() *http.Client {
if httpClient == nil {
httpClient = &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
}
}
return httpClient
}

func GetNotebook(jobID string) (*models.GetNotebook2Result, error) {
var result models.GetNotebook2Result

client := getHttpClient()
s := core.Signer{
Key: setting.ModelartsCD.AccessKey,
Secret: setting.ModelartsCD.SecretKey,
}
r, _ := http.NewRequest(http.MethodGet,
setting.ModelartsCD.EndPoint+"/v1/"+setting.ModelartsCD.ProjectID+urlNotebook2+"/"+jobID,
nil)

r.Header.Add("content-type", "application/json")
s.Sign(r)

resp, err := client.Do(r)
if err != nil {
log.Error("client.Do failed: %s", err.Error())
return &result, fmt.Errorf("client.Do failed: %s", err.Error())
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("ioutil.ReadAll failed: %s", err.Error())
return &result, fmt.Errorf("ioutil.ReadAll failed: %s", err.Error())
}

err = json.Unmarshal(body, &result)
if err != nil {
log.Error("json.Unmarshal failed: %s", err.Error())
return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error())
}

if len(result.ErrorCode) != 0 {
log.Error("GetNotebook failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf("GetNotebook failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
}

func ManageNotebook(jobID string, param models.NotebookAction) (*models.NotebookActionResult, error) {
var result models.NotebookActionResult

client := getHttpClient()
s := core.Signer{
Key: setting.ModelartsCD.AccessKey,
Secret: setting.ModelartsCD.SecretKey,
}
r, _ := http.NewRequest(http.MethodPost,
setting.ModelartsCD.EndPoint+"/v1/"+setting.ModelartsCD.ProjectID+urlNotebook2+"/"+jobID+"/"+param.Action+"?duration="+strconv.Itoa(autoStopDurationMs),
nil)

r.Header.Add("content-type", "application/json")
s.Sign(r)

resp, err := client.Do(r)
if err != nil {
log.Error("client.Do failed: %s", err.Error())
return &result, fmt.Errorf("client.Do failed: %s", err.Error())
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("ioutil.ReadAll failed: %s", err.Error())
return &result, fmt.Errorf("ioutil.ReadAll failed: %s", err.Error())
}

err = json.Unmarshal(body, &result)
if err != nil {
log.Error("json.Unmarshal failed: %s", err.Error())
return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error())
}

if len(result.ErrorCode) != 0 {
log.Error("ManageNotebook2 failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf("ManageNotebook failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
}

func DelNotebook(jobID string) (*models.NotebookDelResult, error) {
var result models.NotebookDelResult

client := getHttpClient()
s := core.Signer{
Key: setting.ModelartsCD.AccessKey,
Secret: setting.ModelartsCD.SecretKey,
}

r, _ := http.NewRequest(http.MethodDelete,
setting.ModelartsCD.EndPoint+"/v1/"+setting.ModelartsCD.ProjectID+urlNotebook2+"/"+jobID,
nil)

r.Header.Add("content-type", "application/json")
s.Sign(r)

resp, err := client.Do(r)
if err != nil {
log.Error("client.Do failed: %s", err.Error())
return &result, fmt.Errorf("client.Do failed: %s", err.Error())
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("ioutil.ReadAll failed: %s", err.Error())
return &result, fmt.Errorf("ioutil.ReadAll failed: %s", err.Error())
}

err = json.Unmarshal(body, &result)
if err != nil {
log.Error("json.Unmarshal failed: %s", err.Error())
return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error())
}

if len(result.ErrorCode) != 0 {
log.Error("DelNotebook2 failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf("DelNotebook2 failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
}

func createNotebook(createJobParams models.CreateNotebookWithoutPoolParams) (*models.CreateNotebookResult, error) {
var result models.CreateNotebookResult
client := getHttpClient()
s := core.Signer{
Key: setting.ModelartsCD.AccessKey,
Secret: setting.ModelartsCD.SecretKey,
}

req, _ := json.Marshal(createJobParams)
r, _ := http.NewRequest(http.MethodPost,
setting.ModelartsCD.EndPoint+"/v1/"+setting.ModelartsCD.ProjectID+urlNotebook2,
ioutil.NopCloser(bytes.NewBuffer(req)))

r.Header.Add("content-type", "application/json")
s.Sign(r)

resp, err := client.Do(r)
if err != nil {
log.Error("client.Do failed: %s", err.Error())
return &result, fmt.Errorf("client.Do failed: %s", err.Error())
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("ioutil.ReadAll failed: %s", err.Error())
return &result, fmt.Errorf("ioutil.ReadAll failed: %s", err.Error())
}

err = json.Unmarshal(body, &result)
if err != nil {
log.Error("json.Unmarshal failed: %s", err.Error())
return &result, fmt.Errorf("json.Unmarshal failed: %s", err.Error())
}

if len(result.ErrorCode) != 0 {
log.Error("createNotebook failed(%s): %s", result.ErrorCode, result.ErrorMsg)
if result.ErrorCode == errorCodeExceedLimit {
result.ErrorMsg = "所选规格使用数量已超过最大配额限制。"
}
return &result, fmt.Errorf("createNotebook failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
}

+ 42
- 0
modules/modelarts_gateway/core/escape.go View File

@@ -0,0 +1,42 @@
// based on https://github.com/golang/go/blob/master/src/net/url/url.go
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package core

func shouldEscape(c byte) bool {
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c == '-' || c == '~' || c == '.' {
return false
}
return true
}
func escape(s string) string {
hexCount := 0
for i := 0; i < len(s); i++ {
c := s[i]
if shouldEscape(c) {
hexCount++
}
}

if hexCount == 0 {
return s
}

t := make([]byte, len(s)+2*hexCount)
j := 0
for i := 0; i < len(s); i++ {
switch c := s[i]; {
case shouldEscape(c):
t[j] = '%'
t[j+1] = "0123456789ABCDEF"[c>>4]
t[j+2] = "0123456789ABCDEF"[c&15]
j += 3
default:
t[j] = s[i]
j++
}
}
return string(t)
}

+ 208
- 0
modules/modelarts_gateway/core/signer.go View File

@@ -0,0 +1,208 @@
// HWS API Gateway Signature
// based on https://github.com/datastream/aws/blob/master/signv4.go
// Copyright (c) 2014, Xianjie

package core

import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"fmt"
"io/ioutil"
"net/http"
"sort"
"strings"
"time"
)

const (
BasicDateFormat = "20060102T150405Z"
Algorithm = "SDK-HMAC-SHA256"
HeaderXDate = "X-Sdk-Date"
HeaderHost = "host"
HeaderAuthorization = "Authorization"
HeaderContentSha256 = "X-Sdk-Content-Sha256"
)

func hmacsha256(key []byte, data string) ([]byte, error) {
h := hmac.New(sha256.New, []byte(key))
if _, err := h.Write([]byte(data)); err != nil {
return nil, err
}
return h.Sum(nil), nil
}

// Build a CanonicalRequest from a regular request string
//
// CanonicalRequest =
// HTTPRequestMethod + '\n' +
// CanonicalURI + '\n' +
// CanonicalQueryString + '\n' +
// CanonicalHeaders + '\n' +
// SignedHeaders + '\n' +
// HexEncode(Hash(RequestPayload))
func CanonicalRequest(r *http.Request, signedHeaders []string) (string, error) {
var hexencode string
var err error
if hex := r.Header.Get(HeaderContentSha256); hex != "" {
hexencode = hex
} else {
data, err := RequestPayload(r)
if err != nil {
return "", err
}
hexencode, err = HexEncodeSHA256Hash(data)
if err != nil {
return "", err
}
}
return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", r.Method, CanonicalURI(r), CanonicalQueryString(r), CanonicalHeaders(r, signedHeaders), strings.Join(signedHeaders, ";"), hexencode), err
}

// CanonicalURI returns request uri
func CanonicalURI(r *http.Request) string {
pattens := strings.Split(r.URL.Path, "/")
var uri []string
for _, v := range pattens {
uri = append(uri, escape(v))
}
urlpath := strings.Join(uri, "/")
if len(urlpath) == 0 || urlpath[len(urlpath)-1] != '/' {
urlpath = urlpath + "/"
}
return urlpath
}

// CanonicalQueryString
func CanonicalQueryString(r *http.Request) string {
var keys []string
query := r.URL.Query()
for key := range query {
keys = append(keys, key)
}
sort.Strings(keys)
var a []string
for _, key := range keys {
k := escape(key)
sort.Strings(query[key])
for _, v := range query[key] {
kv := fmt.Sprintf("%s=%s", k, escape(v))
a = append(a, kv)
}
}
queryStr := strings.Join(a, "&")
r.URL.RawQuery = queryStr
return queryStr
}

// CanonicalHeaders
func CanonicalHeaders(r *http.Request, signerHeaders []string) string {
var a []string
header := make(map[string][]string)
for k, v := range r.Header {
header[strings.ToLower(k)] = v
}
for _, key := range signerHeaders {
value := header[key]
if strings.EqualFold(key, HeaderHost) {
value = []string{r.Host}
}
sort.Strings(value)
for _, v := range value {
a = append(a, key+":"+strings.TrimSpace(v))
}
}
return fmt.Sprintf("%s\n", strings.Join(a, "\n"))
}

// SignedHeaders
func SignedHeaders(r *http.Request) []string {
var a []string
for key := range r.Header {
a = append(a, strings.ToLower(key))
}
sort.Strings(a)
return a
}

// RequestPayload
func RequestPayload(r *http.Request) ([]byte, error) {
if r.Body == nil {
return []byte(""), nil
}
b, err := ioutil.ReadAll(r.Body)
if err != nil {
return []byte(""), err
}
r.Body = ioutil.NopCloser(bytes.NewBuffer(b))
return b, err
}

// Create a "String to Sign".
func StringToSign(canonicalRequest string, t time.Time) (string, error) {
hash := sha256.New()
_, err := hash.Write([]byte(canonicalRequest))
if err != nil {
return "", err
}
return fmt.Sprintf("%s\n%s\n%x",
Algorithm, t.UTC().Format(BasicDateFormat), hash.Sum(nil)), nil
}

// Create the HWS Signature.
func SignStringToSign(stringToSign string, signingKey []byte) (string, error) {
hm, err := hmacsha256(signingKey, stringToSign)
return fmt.Sprintf("%x", hm), err
}

// HexEncodeSHA256Hash returns hexcode of sha256
func HexEncodeSHA256Hash(body []byte) (string, error) {
hash := sha256.New()
if body == nil {
body = []byte("")
}
_, err := hash.Write(body)
return fmt.Sprintf("%x", hash.Sum(nil)), err
}

// Get the finalized value for the "Authorization" header. The signature parameter is the output from SignStringToSign
func AuthHeaderValue(signature, accessKey string, signedHeaders []string) string {
return fmt.Sprintf("%s Access=%s, SignedHeaders=%s, Signature=%s", Algorithm, accessKey, strings.Join(signedHeaders, ";"), signature)
}

// Signature HWS meta
type Signer struct {
Key string
Secret string
}

// SignRequest set Authorization header
func (s *Signer) Sign(r *http.Request) error {
var t time.Time
var err error
var dt string
if dt = r.Header.Get(HeaderXDate); dt != "" {
t, err = time.Parse(BasicDateFormat, dt)
}
if err != nil || dt == "" {
t = time.Now()
r.Header.Set(HeaderXDate, t.UTC().Format(BasicDateFormat))
}
signedHeaders := SignedHeaders(r)
canonicalRequest, err := CanonicalRequest(r, signedHeaders)
if err != nil {
return err
}
stringToSign, err := StringToSign(canonicalRequest, t)
if err != nil {
return err
}
signature, err := SignStringToSign(stringToSign, []byte(s.Secret))
if err != nil {
return err
}
authValue := AuthHeaderValue(signature, s.Key, signedHeaders)
r.Header.Set(HeaderAuthorization, authValue)
return nil
}

+ 73
- 7
modules/setting/setting.go View File

@@ -75,6 +75,26 @@ type C2NetSqInfos struct {
C2NetSqInfo []*C2NetSequenceInfo `json:"sequence"` C2NetSqInfo []*C2NetSequenceInfo `json:"sequence"`
} }


type StFlavorInfos struct {
FlavorInfo []*FlavorInfo `json:"flavor_info"`
}

type FlavorInfo struct {
Id int `json:"id"`
Value string `json:"value"`
Desc string `json:"desc"`
}

type StImageInfosModelArts struct {
ImageInfo []*ImageInfoModelArts `json:"image_info"`
}

type ImageInfoModelArts struct {
Id string `json:"id"`
Value string `json:"value"`
Desc string `json:"desc"`
}

var ( var (
// AppVer settings // AppVer settings
AppVer string AppVer string
@@ -535,20 +555,32 @@ var (
AllowedOrg string AllowedOrg string
ProfileID string ProfileID string
PoolInfos string PoolInfos string
Flavor string
FlavorInfos string
DebugHost string DebugHost string
ImageInfos string ImageInfos string
Capacity int Capacity int
MaxTempQueryTimes int MaxTempQueryTimes int
StFlavorInfo *StFlavorInfos
StImageInfos *StImageInfosModelArts
//train-job //train-job
ResourcePools string ResourcePools string
Engines string Engines string
EngineVersions string EngineVersions string
FlavorInfos string
TrainJobFLAVORINFOS string TrainJobFLAVORINFOS string
ModelArtsSpecialPools string ModelArtsSpecialPools string
ModelArtsMultiNode string ModelArtsMultiNode string


// modelarts-cd config
ModelartsCD = struct {
Enabled bool
EndPoint string
ProjectID string
AccessKey string
SecretKey string
ImageInfos string
FlavorInfos string
}{}

//grampus config //grampus config
Grampus = struct { Grampus = struct {
Env string Env string
@@ -1423,9 +1455,8 @@ func NewContext() {
AllowedOrg = sec.Key("ORGANIZATION").MustString("") AllowedOrg = sec.Key("ORGANIZATION").MustString("")
ProfileID = sec.Key("PROFILE_ID").MustString("") ProfileID = sec.Key("PROFILE_ID").MustString("")
PoolInfos = sec.Key("POOL_INFOS").MustString("") PoolInfos = sec.Key("POOL_INFOS").MustString("")
Flavor = sec.Key("FLAVOR").MustString("")
ImageInfos = sec.Key("IMAGE_INFOS").MustString("") ImageInfos = sec.Key("IMAGE_INFOS").MustString("")
Capacity = sec.Key("IMAGE_INFOS").MustInt(100)
Capacity = sec.Key("CAPACITY").MustInt(100)
MaxTempQueryTimes = sec.Key("MAX_TEMP_QUERY_TIMES").MustInt(30) MaxTempQueryTimes = sec.Key("MAX_TEMP_QUERY_TIMES").MustInt(30)
ResourcePools = sec.Key("Resource_Pools").MustString("") ResourcePools = sec.Key("Resource_Pools").MustString("")
Engines = sec.Key("Engines").MustString("") Engines = sec.Key("Engines").MustString("")
@@ -1474,8 +1505,8 @@ func NewContext() {
Course.OrgName = sec.Key("org_name").MustString("") Course.OrgName = sec.Key("org_name").MustString("")
Course.TeamName = sec.Key("team_name").MustString("") Course.TeamName = sec.Key("team_name").MustString("")


GetGrampusConfig()
getGrampusConfig()
getModelartsCDConfig()
getModelConvertConfig() getModelConvertConfig()
} }


@@ -1498,7 +1529,22 @@ func getModelConvertConfig() {
ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35) ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35)
} }


func GetGrampusConfig() {
func getModelartsCDConfig() {
sec := Cfg.Section("modelarts-cd")

ModelartsCD.Enabled = sec.Key("ENABLED").MustBool(false)
ModelartsCD.EndPoint = sec.Key("ENDPOINT").MustString("https://modelarts.cn-southwest-228.cdzs.cn")
ModelartsCD.ProjectID = sec.Key("PROJECT_ID").MustString("")
ModelartsCD.AccessKey = sec.Key("ACCESS_KEY").MustString("")
ModelartsCD.SecretKey = sec.Key("SECRET_KEY").MustString("")
ModelartsCD.ImageInfos = sec.Key("IMAGE_INFOS").MustString("")
ModelartsCD.FlavorInfos = sec.Key("FLAVOR_INFOS").MustString("")

getNotebookImageInfos()
getNotebookFlavorInfos()
}

func getGrampusConfig() {
sec := Cfg.Section("grampus") sec := Cfg.Section("grampus")


Grampus.Env = sec.Key("ENV").MustString("TEST") Grampus.Env = sec.Key("ENV").MustString("TEST")
@@ -1632,6 +1678,26 @@ func ensureLFSDirectory() {
} }
} }


func getNotebookImageInfos() {
if StImageInfos == nil {
if ModelartsCD.Enabled {
json.Unmarshal([]byte(ModelartsCD.ImageInfos), &StImageInfos)
} else {
json.Unmarshal([]byte(ImageInfos), &StImageInfos)
}
}
}

func getNotebookFlavorInfos() {
if StFlavorInfo == nil {
if ModelartsCD.Enabled {
json.Unmarshal([]byte(ModelartsCD.FlavorInfos), &StFlavorInfo)
} else {
json.Unmarshal([]byte(FlavorInfos), &StFlavorInfo)
}
}
}

// NewServices initializes the services // NewServices initializes the services
func NewServices() { func NewServices() {
InitDBConfig() InitDBConfig()


+ 1
- 0
options/locale/locale_en-US.ini View File

@@ -1079,6 +1079,7 @@ balance.total_view = Total Balance
balance.available = Available Balance: balance.available = Available Balance:
cloudbrain1 = cloudbrain1 cloudbrain1 = cloudbrain1
cloudbrain2 = cloudbrain2 cloudbrain2 = cloudbrain2
cdCenter = cd_ai_center
cloudbrain_selection = select cloudbrain cloudbrain_selection = select cloudbrain
cloudbrain_platform_selection = Select the cloudbrain platform you want to use: cloudbrain_platform_selection = Select the cloudbrain platform you want to use:
confirm_choice = Confirm confirm_choice = Confirm


+ 1
- 0
options/locale/locale_zh-CN.ini View File

@@ -1080,6 +1080,7 @@ balance.total_view=余额总览
balance.available=可用余额: balance.available=可用余额:
cloudbrain1=云脑1 cloudbrain1=云脑1
cloudbrain2=云脑2 cloudbrain2=云脑2
cdCenter=成都智算中心
intelligent_net=智算网络 intelligent_net=智算网络
cloudbrain_selection=云脑选择 cloudbrain_selection=云脑选择
cloudbrain_platform_selection=选择您准备使用的云脑平台: cloudbrain_platform_selection=选择您准备使用的云脑平台:


+ 5
- 3
routers/repo/cloudbrain.go View File

@@ -2765,6 +2765,8 @@ func GetCloudbrainAiCenter(task models.Cloudbrain, ctx *context.Context) string
return ctx.Tr("repo.cloudbrain1") return ctx.Tr("repo.cloudbrain1")
} else if task.Type == models.TypeCloudBrainTwo { } else if task.Type == models.TypeCloudBrainTwo {
return ctx.Tr("repo.cloudbrain2") return ctx.Tr("repo.cloudbrain2")
} else if task.Type == models.TypeCDCenter {
return ctx.Tr("repo.cdCenter")
} else if task.Type == models.TypeC2Net { } else if task.Type == models.TypeC2Net {
return getCutStringAiCenterByAiCenter(task.AiCenter) return getCutStringAiCenterByAiCenter(task.AiCenter)
} }
@@ -2779,7 +2781,7 @@ func getCutStringAiCenterByAiCenter(aiCenter string) string {


} }
func GetCloudbrainCluster(task models.Cloudbrain, ctx *context.Context) string { func GetCloudbrainCluster(task models.Cloudbrain, ctx *context.Context) string {
if task.Type == models.TypeCloudBrainOne || task.Type == models.TypeCloudBrainTwo {
if task.Type == models.TypeCloudBrainOne || task.Type == models.TypeCloudBrainTwo || task.Type == models.TypeCDCenter {
return ctx.Tr("cloudbrain.resource_cluster_openi") return ctx.Tr("cloudbrain.resource_cluster_openi")
} else if task.Type == models.TypeC2Net { } else if task.Type == models.TypeC2Net {
return ctx.Tr("cloudbrain.resource_cluster_c2net") return ctx.Tr("cloudbrain.resource_cluster_c2net")
@@ -2866,10 +2868,10 @@ func GetCloudbrainFlavorName(task models.Cloudbrain) (string, error) {
return CloudbrainOneFlavorName, nil return CloudbrainOneFlavorName, nil
} }
} }
} else if (task.Type == models.TypeCloudBrainTwo || task.Type == models.TypeC2Net) && task.FlavorName != "" {
} else if (task.Type == models.TypeCloudBrainTwo || task.Type == models.TypeC2Net || task.Type == models.TypeCDCenter) && task.FlavorName != "" {
replaceFlavorName := strings.ReplaceAll(task.FlavorName, ":", ":") replaceFlavorName := strings.ReplaceAll(task.FlavorName, ":", ":")
return replaceFlavorName, nil return replaceFlavorName, nil
} else if task.Type == models.TypeCloudBrainTwo && task.FlavorName == "" && task.FlavorCode != "" {
} else if (task.Type == models.TypeCloudBrainTwo || task.Type == models.TypeCDCenter) && task.FlavorName == "" && task.FlavorCode != "" {
cloudbrainTwoFlavorName := getFlavorNameByFlavorCode(task.FlavorCode) cloudbrainTwoFlavorName := getFlavorNameByFlavorCode(task.FlavorCode)
return cloudbrainTwoFlavorName, nil return cloudbrainTwoFlavorName, nil
} else if task.Type == models.TypeCloudBrainTwo && task.JobType == string(models.JobTypeDebug) && task.FlavorName == "" && task.FlavorCode == "" { } else if task.Type == models.TypeCloudBrainTwo && task.JobType == string(models.JobTypeDebug) && task.FlavorName == "" && task.FlavorCode == "" {


+ 71
- 127
routers/repo/modelarts.go View File

@@ -2,6 +2,7 @@ package repo


import ( import (
"archive/zip" "archive/zip"
"code.gitea.io/gitea/modules/modelarts_cd"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@@ -60,18 +61,11 @@ func DebugJobIndex(ctx *context.Context) {
if page <= 0 { if page <= 0 {
page = 1 page = 1
} }
typeCloudBrain := models.TypeCloudBrainAll
jobTypeNot := false jobTypeNot := false
if listType == models.GPUResource {
typeCloudBrain = models.TypeCloudBrainOne
} else if listType == models.NPUResource {
typeCloudBrain = models.TypeCloudBrainTwo
} else if listType == models.AllResource {
typeCloudBrain = models.TypeCloudBrainAll
} else {
log.Error("listType(%s) error", listType)
ctx.ServerError("listType error", errors.New("listType error"))
return
var computeResource string
if listType != models.AllResource {
computeResource = listType
} }


var jobTypes []string var jobTypes []string
@@ -81,10 +75,11 @@ func DebugJobIndex(ctx *context.Context) {
Page: page, Page: page,
PageSize: setting.UI.IssuePagingNum, PageSize: setting.UI.IssuePagingNum,
}, },
RepoID: repo.ID,
Type: typeCloudBrain,
JobTypeNot: jobTypeNot,
JobTypes: jobTypes,
RepoID: repo.ID,
ComputeResource: computeResource,
Type: models.TypeCloudBrainAll,
JobTypeNot: jobTypeNot,
JobTypes: jobTypes,
}) })
if err != nil { if err != nil {
ctx.ServerError("Get debugjob faild:", err) ctx.ServerError("Get debugjob faild:", err)
@@ -134,16 +129,8 @@ func notebookNewDataPrepare(ctx *context.Context) error {
return err return err
} }
ctx.Data["attachments"] = attachs ctx.Data["attachments"] = attachs

if modelarts.ImageInfos == nil {
json.Unmarshal([]byte(setting.ImageInfos), &modelarts.ImageInfos)
}
ctx.Data["images"] = modelarts.ImageInfos.ImageInfo

if modelarts.FlavorInfos == nil {
json.Unmarshal([]byte(setting.FlavorInfos), &modelarts.FlavorInfos)
}
ctx.Data["flavors"] = modelarts.FlavorInfos.FlavorInfo
ctx.Data["images"] = setting.StImageInfos.ImageInfo
ctx.Data["flavors"] = setting.StFlavorInfo.FlavorInfo
setSpecBySpecialPoolConfig(ctx, string(models.JobTypeDebug)) setSpecBySpecialPoolConfig(ctx, string(models.JobTypeDebug))


ctx.Data["datasetType"] = models.TypeCloudBrainTwo ctx.Data["datasetType"] = models.TypeCloudBrainTwo
@@ -154,50 +141,6 @@ func notebookNewDataPrepare(ctx *context.Context) error {
return nil return nil
} }


func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm) {
ctx.Data["PageIsNotebook"] = true
jobName := form.JobName
uuid := form.Attachment
description := form.Description
flavor := form.Flavor

count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplModelArtsNotebookNew, &form)
return
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsNotebookNew, &form)
return
}
}
_, err = models.GetCloudbrainByName(jobName)
if err == nil {
log.Error("the job name did already exist", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("the job name did already exist", tplModelArtsNotebookNew, &form)
return
} else {
if !models.IsErrJobNotExist(err) {
log.Error("system error, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplModelArtsNotebookNew, &form)
return
}
}

err = modelarts.GenerateTask(ctx, jobName, uuid, description, flavor)
if err != nil {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm) { func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm) {
ctx.Data["PageIsNotebook"] = true ctx.Data["PageIsNotebook"] = true
displayJobName := form.DisplayJobName displayJobName := form.DisplayJobName
@@ -247,7 +190,12 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm
return return
} }


err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, uuid, description, flavor, imageId)
if setting.ModelartsCD.Enabled {
err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, uuid, description, flavor, imageId)
} else {
err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, uuid, description, flavor, imageId)
}

if err != nil { if err != nil {
log.Error("GenerateNotebook2 failed, %v", err, ctx.Data["MsgID"]) log.Error("GenerateNotebook2 failed, %v", err, ctx.Data["MsgID"])
notebookNewDataPrepare(ctx) notebookNewDataPrepare(ctx)
@@ -292,14 +240,11 @@ func NotebookShow(ctx *context.Context) {
if err == nil { if err == nil {
task.User = user task.User = user
} }
if modelarts.FlavorInfos == nil {
json.Unmarshal([]byte(setting.FlavorInfos), &modelarts.FlavorInfos)
}


findSpec := false findSpec := false
if modelarts.FlavorInfos != nil {
ctx.Data["resource_spec"] = modelarts.FlavorInfos.FlavorInfo[0].Desc
for _, f := range modelarts.FlavorInfos.FlavorInfo {
if setting.StFlavorInfo != nil {
ctx.Data["resource_spec"] = setting.StFlavorInfo.FlavorInfo[0].Desc
for _, f := range setting.StFlavorInfo.FlavorInfo {
if fmt.Sprint(f.Value) == task.FlavorCode { if fmt.Sprint(f.Value) == task.FlavorCode {
ctx.Data["resource_spec"] = f.Desc ctx.Data["resource_spec"] = f.Desc
findSpec = true findSpec = true
@@ -394,36 +339,16 @@ func setShowSpecBySpecialPoolConfig(ctx *context.Context, findSpec bool, task *m
} }
} }


func NotebookDebug(ctx *context.Context) {
var jobID = ctx.Params(":jobid")

result, err := modelarts.GetJob(jobID)
if err != nil {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookIndex, nil)
return
}

res, err := modelarts.GetJobToken(jobID)
if err != nil {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookIndex, nil)
return
}

urls := strings.Split(result.Spec.Annotations.Url, "/")
urlPrefix := result.Spec.Annotations.TargetDomain
for i, url := range urls {
if i > 2 {
urlPrefix += "/" + url
}
}

debugUrl := urlPrefix + "?token=" + res.Token
ctx.Redirect(debugUrl)
}

func NotebookDebug2(ctx *context.Context) { func NotebookDebug2(ctx *context.Context) {
var err error
var result *models.GetNotebook2Result
task := ctx.Cloudbrain task := ctx.Cloudbrain
result, err := modelarts.GetNotebook2(task.JobID)
if task.Type == models.TypeCloudBrainTwo {
result, err = modelarts.GetNotebook2(task.JobID)
} else if task.Type == models.TypeCDCenter {
result, err = modelarts_cd.GetNotebook(task.JobID)
}

if err != nil { if err != nil {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookIndex, nil) ctx.RenderWithErr(err.Error(), tplModelArtsNotebookIndex, nil)
return return
@@ -469,7 +394,13 @@ func NotebookRestart(ctx *context.Context) {
Action: models.ActionStart, Action: models.ActionStart,
} }


res, err := modelarts.ManageNotebook2(task.JobID, param)
var res *models.NotebookActionResult
if task.Type == models.TypeCloudBrainTwo {
res, err = modelarts.ManageNotebook2(task.JobID, param)
} else if task.Type == models.TypeCDCenter {
res, err = modelarts_cd.ManageNotebook(task.JobID, param)
}

if err != nil { if err != nil {
log.Error("ManageNotebook2(%s) failed:%v", task.DisplayJobName, err.Error(), ctx.Data["MsgID"]) log.Error("ManageNotebook2(%s) failed:%v", task.DisplayJobName, err.Error(), ctx.Data["MsgID"])
/* 暂不处理再次调试502的场景,详情见方案 /* 暂不处理再次调试502的场景,详情见方案
@@ -555,7 +486,14 @@ func NotebookStop(ctx *context.Context) {
Action: models.ActionStop, Action: models.ActionStop,
} }


res, err := modelarts.ManageNotebook2(task.JobID, param)
var err error
var res *models.NotebookActionResult
if task.Type == models.TypeCloudBrainTwo {
res, err = modelarts.ManageNotebook2(task.JobID, param)
} else if task.Type == models.TypeCDCenter {
res, err = modelarts_cd.ManageNotebook(task.JobID, param)
}

if err != nil { if err != nil {
log.Error("ManageNotebook2(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"]) log.Error("ManageNotebook2(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1" resultCode = "-1"
@@ -605,7 +543,13 @@ func NotebookDel(ctx *context.Context) {
return return
} }


_, err := modelarts.DelNotebook2(task.JobID)
var err error
if task.Type == models.TypeCloudBrainTwo {
_, err = modelarts.DelNotebook2(task.JobID)
} else if task.Type == models.TypeCDCenter {
_, err = modelarts_cd.DelNotebook(task.JobID)
}

if err != nil { if err != nil {
log.Error("DelNotebook2(%s) failed:%v", task.JobName, err.Error()) log.Error("DelNotebook2(%s) failed:%v", task.JobName, err.Error())
if strings.Contains(err.Error(), modelarts.NotebookNotFound) || strings.Contains(err.Error(), modelarts.NotebookNoPermission) || strings.Contains(err.Error(), modelarts.NotebookInvalid) { if strings.Contains(err.Error(), modelarts.NotebookNotFound) || strings.Contains(err.Error(), modelarts.NotebookNoPermission) || strings.Contains(err.Error(), modelarts.NotebookInvalid) {
@@ -764,7 +708,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error {
ctx.Data["WaitCount"] = waitCount ctx.Data["WaitCount"] = waitCount


setMultiNodeIfConfigureMatch(ctx) setMultiNodeIfConfigureMatch(ctx)
return nil return nil
} }


@@ -1130,8 +1074,8 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
VersionCount := modelarts.VersionCountOne VersionCount := modelarts.VersionCountOne
EngineName := form.EngineName EngineName := form.EngineName


errStr:=checkMultiNode(ctx.User.ID,form.WorkServerNumber)
if errStr!=""{
errStr := checkMultiNode(ctx.User.ID, form.WorkServerNumber)
if errStr != "" {
trainJobErrorNewDataPrepare(ctx, form) trainJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobNew, &form) ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobNew, &form)
return return
@@ -1371,31 +1315,31 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job")
} }


func checkMultiNode(userId int64, serverNum int) string{
if serverNum==1{
func checkMultiNode(userId int64, serverNum int) string {
if serverNum == 1 {
return "" return ""
} }
modelarts.InitMultiNode() modelarts.InitMultiNode()
var isServerNumValid=false
var isServerNumValid = false
if modelarts.MultiNodeConfig != nil { if modelarts.MultiNodeConfig != nil {
for _, info := range modelarts.MultiNodeConfig.Info { for _, info := range modelarts.MultiNodeConfig.Info {
if isInOrg, _ := models.IsOrganizationMemberByOrgName(info.Org, userId); isInOrg { if isInOrg, _ := models.IsOrganizationMemberByOrgName(info.Org, userId); isInOrg {
if isInNodes(info.Node,serverNum){
isServerNumValid=true
if isInNodes(info.Node, serverNum) {
isServerNumValid = true
break break
} }


} }
} }
} }
if isServerNumValid{
if isServerNumValid {
return "" return ""
}else{
} else {
return "repo.modelarts.no_node_right" return "repo.modelarts.no_node_right"
} }
} }
func checkInferenceJobMultiNode(userId int64, serverNum int) string{
if serverNum==1{
func checkInferenceJobMultiNode(userId int64, serverNum int) string {
if serverNum == 1 {
return "" return ""
} }


@@ -1404,8 +1348,8 @@ func checkInferenceJobMultiNode(userId int64, serverNum int) string{
} }


func isInNodes(nodes []int, num int) bool { func isInNodes(nodes []int, num int) bool {
for _, node:=range nodes{
if node==num{
for _, node := range nodes {
if node == num {
return true return true
} }
} }
@@ -1447,8 +1391,8 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ
ctx.Data["PageIsTrainJob"] = true ctx.Data["PageIsTrainJob"] = true
var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")


errStr:=checkMultiNode(ctx.User.ID,form.WorkServerNumber)
if errStr!=""{
errStr := checkMultiNode(ctx.User.ID, form.WorkServerNumber)
if errStr != "" {
versionErrorDataPrepare(ctx, form) versionErrorDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobVersionNew, &form) ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobVersionNew, &form)
return return
@@ -1789,7 +1733,7 @@ func paramCheckCreateTrainJob(form auth.CreateModelArtsTrainJobForm) error {
log.Error("the boot file(%s) must be a python file", strings.TrimSpace(form.BootFile)) log.Error("the boot file(%s) must be a python file", strings.TrimSpace(form.BootFile))
return errors.New("启动文件必须是python文件") return errors.New("启动文件必须是python文件")
} }
if form.BranchName == "" { if form.BranchName == "" {
log.Error("the branch must not be null!", form.BranchName) log.Error("the branch must not be null!", form.BranchName)
return errors.New("代码分支不能为空!") return errors.New("代码分支不能为空!")
@@ -2088,8 +2032,8 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference
ckptUrl := "/" + form.TrainUrl + form.CkptName ckptUrl := "/" + form.TrainUrl + form.CkptName
log.Info("ckpt url:" + ckptUrl) log.Info("ckpt url:" + ckptUrl)


errStr:=checkInferenceJobMultiNode(ctx.User.ID,form.WorkServerNumber)
if errStr!=""{
errStr := checkInferenceJobMultiNode(ctx.User.ID, form.WorkServerNumber)
if errStr != "" {
inferenceJobErrorNewDataPrepare(ctx, form) inferenceJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsInferenceJobNew, &form) ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsInferenceJobNew, &form)
return return
@@ -2319,7 +2263,7 @@ func checkModelArtsSpecialPool(ctx *context.Context, flavorCode string, jobType
if !isMatchPool { if !isMatchPool {
isMatchSpec := false isMatchSpec := false
if jobType == string(models.JobTypeDebug) { if jobType == string(models.JobTypeDebug) {
for _, flavor := range modelarts.FlavorInfos.FlavorInfo {
for _, flavor := range setting.StFlavorInfo.FlavorInfo {
if flavor.Value == flavorCode { if flavor.Value == flavorCode {
isMatchSpec = true isMatchSpec = true
break break


Loading…
Cancel
Save