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
| @@ -25,7 +25,8 @@ type ModelArtsJobStatus string | |||
| const ( | |||
| TypeCloudBrainOne int = iota | |||
| TypeCloudBrainTwo | |||
| TypeC2Net //智算网络 | |||
| TypeC2Net //智算网络 | |||
| TypeCDCenter //成都智算中心 | |||
| TypeCloudBrainAll = -1 | |||
| ) | |||
| @@ -596,37 +597,17 @@ type ResourceSpec struct { | |||
| 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 { | |||
| Pools []*SpecialPool `json:"pools"` | |||
| } | |||
| 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 { | |||
| @@ -732,6 +713,17 @@ type CreateNotebook2Params struct { | |||
| 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 { | |||
| Capacity int `json:"capacity"` | |||
| Category string `json:"category"` | |||
| @@ -955,6 +947,7 @@ type NotebookGetJobTokenResult struct { | |||
| } | |||
| type NotebookDelResult struct { | |||
| NotebookResult | |||
| 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 opts.JobTypeNot { | |||
| cond = cond.And( | |||
| @@ -1506,7 +1493,7 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||
| if (opts.Cluster) != "" { | |||
| if opts.Cluster == "resource_cluster_openi" { | |||
| 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" { | |||
| @@ -1959,7 +1946,7 @@ func GetWaitingCloudbrainCount(cloudbrainType int, computeResource string, jobTy | |||
| func GetCloudbrainNotebookCountByUserID(userID int64) (int, error) { | |||
| 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 | |||
| } | |||
| @@ -30,8 +30,8 @@ const ( | |||
| var ( | |||
| poolInfos *models.PoolInfos | |||
| FlavorInfos *models.FlavorInfos | |||
| ImageInfos *models.ImageInfosModelArts | |||
| FlavorInfos *setting.StFlavorInfos | |||
| ImageInfos *setting.StImageInfosModelArts | |||
| SpecialPools *models.SpecialPools | |||
| ) | |||
| @@ -1,6 +1,7 @@ | |||
| package modelarts | |||
| import ( | |||
| "code.gitea.io/gitea/modules/modelarts_cd" | |||
| "encoding/json" | |||
| "errors" | |||
| "fmt" | |||
| @@ -68,8 +69,6 @@ const ( | |||
| var ( | |||
| poolInfos *models.PoolInfos | |||
| FlavorInfos *models.FlavorInfos | |||
| ImageInfos *models.ImageInfosModelArts | |||
| TrainFlavorInfos *Flavor | |||
| SpecialPools *models.SpecialPools | |||
| MultiNodeConfig *MultiNodes | |||
| @@ -757,11 +756,7 @@ func GetNotebookImageName(imageId string) (string, error) { | |||
| var validImage = false | |||
| 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 { | |||
| validImage = true | |||
| imageName = imageInfo.Value | |||
| @@ -825,8 +820,13 @@ func HandleTrainJobInfo(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 { | |||
| log.Error("GetNotebook2(%s) failed:%v", task.DisplayJobName, err) | |||
| return err | |||
| @@ -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 | |||
| } | |||
| */ | |||
| @@ -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 | |||
| } | |||
| @@ -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) | |||
| } | |||
| @@ -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 | |||
| } | |||
| @@ -75,6 +75,26 @@ type C2NetSqInfos struct { | |||
| 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 ( | |||
| // AppVer settings | |||
| AppVer string | |||
| @@ -535,20 +555,32 @@ var ( | |||
| AllowedOrg string | |||
| ProfileID string | |||
| PoolInfos string | |||
| Flavor string | |||
| FlavorInfos string | |||
| DebugHost string | |||
| ImageInfos string | |||
| Capacity int | |||
| MaxTempQueryTimes int | |||
| StFlavorInfo *StFlavorInfos | |||
| StImageInfos *StImageInfosModelArts | |||
| //train-job | |||
| ResourcePools string | |||
| Engines string | |||
| EngineVersions string | |||
| FlavorInfos string | |||
| TrainJobFLAVORINFOS string | |||
| ModelArtsSpecialPools 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 = struct { | |||
| Env string | |||
| @@ -1423,9 +1455,8 @@ func NewContext() { | |||
| AllowedOrg = sec.Key("ORGANIZATION").MustString("") | |||
| ProfileID = sec.Key("PROFILE_ID").MustString("") | |||
| PoolInfos = sec.Key("POOL_INFOS").MustString("") | |||
| Flavor = sec.Key("FLAVOR").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) | |||
| ResourcePools = sec.Key("Resource_Pools").MustString("") | |||
| Engines = sec.Key("Engines").MustString("") | |||
| @@ -1474,8 +1505,8 @@ func NewContext() { | |||
| Course.OrgName = sec.Key("org_name").MustString("") | |||
| Course.TeamName = sec.Key("team_name").MustString("") | |||
| GetGrampusConfig() | |||
| getGrampusConfig() | |||
| getModelartsCDConfig() | |||
| getModelConvertConfig() | |||
| } | |||
| @@ -1498,7 +1529,22 @@ func getModelConvertConfig() { | |||
| 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") | |||
| 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 | |||
| func NewServices() { | |||
| InitDBConfig() | |||
| @@ -1079,6 +1079,7 @@ balance.total_view = Total Balance | |||
| balance.available = Available Balance: | |||
| cloudbrain1 = cloudbrain1 | |||
| cloudbrain2 = cloudbrain2 | |||
| cdCenter = cd_ai_center | |||
| cloudbrain_selection = select cloudbrain | |||
| cloudbrain_platform_selection = Select the cloudbrain platform you want to use: | |||
| confirm_choice = Confirm | |||
| @@ -1080,6 +1080,7 @@ balance.total_view=余额总览 | |||
| balance.available=可用余额: | |||
| cloudbrain1=云脑1 | |||
| cloudbrain2=云脑2 | |||
| cdCenter=成都智算中心 | |||
| intelligent_net=智算网络 | |||
| cloudbrain_selection=云脑选择 | |||
| cloudbrain_platform_selection=选择您准备使用的云脑平台: | |||
| @@ -2765,6 +2765,8 @@ func GetCloudbrainAiCenter(task models.Cloudbrain, ctx *context.Context) string | |||
| return ctx.Tr("repo.cloudbrain1") | |||
| } else if task.Type == models.TypeCloudBrainTwo { | |||
| return ctx.Tr("repo.cloudbrain2") | |||
| } else if task.Type == models.TypeCDCenter { | |||
| return ctx.Tr("repo.cdCenter") | |||
| } else if task.Type == models.TypeC2Net { | |||
| return getCutStringAiCenterByAiCenter(task.AiCenter) | |||
| } | |||
| @@ -2779,7 +2781,7 @@ func getCutStringAiCenterByAiCenter(aiCenter string) 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") | |||
| } else if task.Type == models.TypeC2Net { | |||
| return ctx.Tr("cloudbrain.resource_cluster_c2net") | |||
| @@ -2866,10 +2868,10 @@ func GetCloudbrainFlavorName(task models.Cloudbrain) (string, error) { | |||
| 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, ":", ":") | |||
| 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) | |||
| return cloudbrainTwoFlavorName, nil | |||
| } else if task.Type == models.TypeCloudBrainTwo && task.JobType == string(models.JobTypeDebug) && task.FlavorName == "" && task.FlavorCode == "" { | |||
| @@ -2,6 +2,7 @@ package repo | |||
| import ( | |||
| "archive/zip" | |||
| "code.gitea.io/gitea/modules/modelarts_cd" | |||
| "encoding/json" | |||
| "errors" | |||
| "fmt" | |||
| @@ -60,18 +61,11 @@ func DebugJobIndex(ctx *context.Context) { | |||
| if page <= 0 { | |||
| page = 1 | |||
| } | |||
| typeCloudBrain := models.TypeCloudBrainAll | |||
| 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 | |||
| @@ -81,10 +75,11 @@ func DebugJobIndex(ctx *context.Context) { | |||
| Page: page, | |||
| 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 { | |||
| ctx.ServerError("Get debugjob faild:", err) | |||
| @@ -134,16 +129,8 @@ func notebookNewDataPrepare(ctx *context.Context) error { | |||
| return err | |||
| } | |||
| 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)) | |||
| ctx.Data["datasetType"] = models.TypeCloudBrainTwo | |||
| @@ -154,50 +141,6 @@ func notebookNewDataPrepare(ctx *context.Context) error { | |||
| 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) { | |||
| ctx.Data["PageIsNotebook"] = true | |||
| displayJobName := form.DisplayJobName | |||
| @@ -247,7 +190,12 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm | |||
| 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 { | |||
| log.Error("GenerateNotebook2 failed, %v", err, ctx.Data["MsgID"]) | |||
| notebookNewDataPrepare(ctx) | |||
| @@ -292,14 +240,11 @@ func NotebookShow(ctx *context.Context) { | |||
| if err == nil { | |||
| task.User = user | |||
| } | |||
| if modelarts.FlavorInfos == nil { | |||
| json.Unmarshal([]byte(setting.FlavorInfos), &modelarts.FlavorInfos) | |||
| } | |||
| 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 { | |||
| ctx.Data["resource_spec"] = f.Desc | |||
| 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) { | |||
| var err error | |||
| var result *models.GetNotebook2Result | |||
| 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 { | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsNotebookIndex, nil) | |||
| return | |||
| @@ -469,7 +394,13 @@ func NotebookRestart(ctx *context.Context) { | |||
| 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 { | |||
| log.Error("ManageNotebook2(%s) failed:%v", task.DisplayJobName, err.Error(), ctx.Data["MsgID"]) | |||
| /* 暂不处理再次调试502的场景,详情见方案 | |||
| @@ -555,7 +486,14 @@ func NotebookStop(ctx *context.Context) { | |||
| 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 { | |||
| log.Error("ManageNotebook2(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"]) | |||
| resultCode = "-1" | |||
| @@ -605,7 +543,13 @@ func NotebookDel(ctx *context.Context) { | |||
| 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 { | |||
| 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) { | |||
| @@ -764,7 +708,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error { | |||
| ctx.Data["WaitCount"] = waitCount | |||
| setMultiNodeIfConfigureMatch(ctx) | |||
| return nil | |||
| } | |||
| @@ -1130,8 +1074,8 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
| VersionCount := modelarts.VersionCountOne | |||
| EngineName := form.EngineName | |||
| errStr:=checkMultiNode(ctx.User.ID,form.WorkServerNumber) | |||
| if errStr!=""{ | |||
| errStr := checkMultiNode(ctx.User.ID, form.WorkServerNumber) | |||
| if errStr != "" { | |||
| trainJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobNew, &form) | |||
| return | |||
| @@ -1371,31 +1315,31 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
| 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 "" | |||
| } | |||
| modelarts.InitMultiNode() | |||
| var isServerNumValid=false | |||
| var isServerNumValid = false | |||
| if modelarts.MultiNodeConfig != nil { | |||
| for _, info := range modelarts.MultiNodeConfig.Info { | |||
| if isInOrg, _ := models.IsOrganizationMemberByOrgName(info.Org, userId); isInOrg { | |||
| if isInNodes(info.Node,serverNum){ | |||
| isServerNumValid=true | |||
| if isInNodes(info.Node, serverNum) { | |||
| isServerNumValid = true | |||
| break | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if isServerNumValid{ | |||
| if isServerNumValid { | |||
| return "" | |||
| }else{ | |||
| } else { | |||
| 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 "" | |||
| } | |||
| @@ -1404,8 +1348,8 @@ func checkInferenceJobMultiNode(userId int64, serverNum int) string{ | |||
| } | |||
| func isInNodes(nodes []int, num int) bool { | |||
| for _, node:=range nodes{ | |||
| if node==num{ | |||
| for _, node := range nodes { | |||
| if node == num { | |||
| return true | |||
| } | |||
| } | |||
| @@ -1447,8 +1391,8 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||
| ctx.Data["PageIsTrainJob"] = true | |||
| 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) | |||
| ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobVersionNew, &form) | |||
| 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)) | |||
| return errors.New("启动文件必须是python文件") | |||
| } | |||
| if form.BranchName == "" { | |||
| log.Error("the branch must not be null!", form.BranchName) | |||
| return errors.New("代码分支不能为空!") | |||
| @@ -2088,8 +2032,8 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference | |||
| ckptUrl := "/" + form.TrainUrl + form.CkptName | |||
| 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) | |||
| ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsInferenceJobNew, &form) | |||
| return | |||
| @@ -2319,7 +2263,7 @@ func checkModelArtsSpecialPool(ctx *context.Context, flavorCode string, jobType | |||
| if !isMatchPool { | |||
| isMatchSpec := false | |||
| if jobType == string(models.JobTypeDebug) { | |||
| for _, flavor := range modelarts.FlavorInfos.FlavorInfo { | |||
| for _, flavor := range setting.StFlavorInfo.FlavorInfo { | |||
| if flavor.Value == flavorCode { | |||
| isMatchSpec = true | |||
| break | |||