@@ -72,11 +72,11 @@ type CloudBrainLoginResult struct { | |||||
type TaskRole struct { | type TaskRole struct { | ||||
Name string `json:"name"` | Name string `json:"name"` | ||||
TaskNumber int `json:"taskNumber"` | |||||
MinSucceededTaskCount int `json:"minSucceededTaskCount"` | |||||
MinFailedTaskCount int `json:"minFailedTaskCount"` | |||||
CPUNumber int `json:"cpuNumber"` | |||||
GPUNumber int `json:"gpuNumber"` | |||||
TaskNumber int `json:"taskNumber"` | |||||
MinSucceededTaskCount int `json:"minSucceededTaskCount"` | |||||
MinFailedTaskCount int `json:"minFailedTaskCount"` | |||||
CPUNumber int `json:"cpuNumber"` | |||||
GPUNumber int `json:"gpuNumber"` | |||||
MemoryMB int `json:"memoryMB"` | MemoryMB int `json:"memoryMB"` | ||||
ShmMB int `json:"shmMB"` | ShmMB int `json:"shmMB"` | ||||
Command string `json:"command"` | Command string `json:"command"` | ||||
@@ -299,6 +299,25 @@ 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"` | |||||
} | |||||
type PoolInfos struct { | |||||
PoolInfo []*PoolInfo `json:"pool_info"` | |||||
} | |||||
type PoolInfo struct { | |||||
PoolId string `json:"pool_id"` | |||||
PoolName string `json:"pool_name"` | |||||
PoolType string `json:"pool_type"` | |||||
} | |||||
type CommitImageParams struct { | type CommitImageParams struct { | ||||
Ip string `json:"ip"` | Ip string `json:"ip"` | ||||
TaskContainerId string `json:"taskContainerId"` | TaskContainerId string `json:"taskContainerId"` | ||||
@@ -87,7 +87,7 @@ func InsertFileChunk(fileChunk *FileChunk) (_ *FileChunk, err error) { | |||||
return fileChunk, nil | return fileChunk, nil | ||||
} | } | ||||
// UpdateAttachment updates the given attachment in database | |||||
// UpdateFileChunk updates the given file_chunk in database | |||||
func UpdateFileChunk(fileChunk *FileChunk) error { | func UpdateFileChunk(fileChunk *FileChunk) error { | ||||
return updateFileChunk(x, fileChunk) | return updateFileChunk(x, fileChunk) | ||||
} | } | ||||
@@ -98,3 +98,13 @@ func updateFileChunk(e Engine, fileChunk *FileChunk) error { | |||||
_, err := sess.Cols("is_uploaded").Update(fileChunk) | _, err := sess.Cols("is_uploaded").Update(fileChunk) | ||||
return err | return err | ||||
} | } | ||||
// DeleteFileChunk delete the given file_chunk in database | |||||
func DeleteFileChunk(fileChunk *FileChunk) error { | |||||
return deleteFileChunk(x, fileChunk) | |||||
} | |||||
func deleteFileChunk(e Engine, fileChunk *FileChunk) error { | |||||
_, err := e.ID(fileChunk.ID).Delete(fileChunk) | |||||
return err | |||||
} |
@@ -82,6 +82,12 @@ sendjob: | |||||
Post(HOST + "/rest-server/api/v1/jobs/") | Post(HOST + "/rest-server/api/v1/jobs/") | ||||
if err != nil { | if err != nil { | ||||
if res != nil { | |||||
var response models.CloudBrainResult | |||||
json.Unmarshal(res.Body(), &response) | |||||
log.Error("code(%s), msg(%s)", response.Code, response.Msg) | |||||
return nil, fmt.Errorf(response.Msg) | |||||
} | |||||
return nil, fmt.Errorf("resty create job: %s", err) | return nil, fmt.Errorf("resty create job: %s", err) | ||||
} | } | ||||
@@ -2,6 +2,7 @@ package modelarts | |||||
import ( | import ( | ||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"encoding/json" | |||||
"path" | "path" | ||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
@@ -12,30 +13,31 @@ import ( | |||||
const ( | const ( | ||||
storageTypeOBS = "obs" | storageTypeOBS = "obs" | ||||
autoStopDuration = 4 * 60 * 60 | autoStopDuration = 4 * 60 * 60 | ||||
flavor = "modelarts.kat1.xlarge" | |||||
//profileID = "Python3-ascend910-arm" | |||||
profileID = "efa847c0-7359-11eb-b34f-0255ac100057" | |||||
poolID = "pool1328035d" | |||||
poolName = "train-private-1" | |||||
poolType = "USER_DEFINED" | |||||
DataSetMountPath = "/home/ma-user/work" | DataSetMountPath = "/home/ma-user/work" | ||||
NotebookEnv = "Python3" | NotebookEnv = "Python3" | ||||
NotebookType = "Ascend" | NotebookType = "Ascend" | ||||
FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)" | |||||
) | |||||
var ( | |||||
poolInfos *models.PoolInfos | |||||
FlavorInfos *models.FlavorInfos | |||||
) | ) | ||||
func GenerateTask(ctx *context.Context, jobName, uuid, description string) error { | func GenerateTask(ctx *context.Context, jobName, uuid, description string) error { | ||||
dataActualPath := setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + "/" | dataActualPath := setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + "/" | ||||
if poolInfos == nil { | |||||
json.Unmarshal([]byte(setting.PoolInfos), &poolInfos) | |||||
} | |||||
jobResult, err := CreateJob(models.CreateNotebookParams{ | jobResult, err := CreateJob(models.CreateNotebookParams{ | ||||
JobName: jobName, | JobName: jobName, | ||||
Description: description, | Description: description, | ||||
ProfileID: profileID, | |||||
Flavor: flavor, | |||||
ProfileID: setting.ProfileID, | |||||
Flavor: setting.Flavor, | |||||
Pool: models.Pool{ | Pool: models.Pool{ | ||||
ID: poolID, | |||||
Name: poolName, | |||||
Type: poolType, | |||||
ID: poolInfos.PoolInfo[0].PoolId, | |||||
Name: poolInfos.PoolInfo[0].PoolName, | |||||
Type: poolInfos.PoolInfo[0].PoolType, | |||||
}, | }, | ||||
Spec: models.Spec{ | Spec: models.Spec{ | ||||
Storage: models.Storage{ | Storage: models.Storage{ | ||||
@@ -473,6 +473,10 @@ var ( | |||||
ModelArtsUsername string | ModelArtsUsername string | ||||
ModelArtsPassword string | ModelArtsPassword string | ||||
ModelArtsDomain string | ModelArtsDomain string | ||||
ProfileID string | |||||
PoolInfos string | |||||
Flavor string | |||||
FlavorInfos string | |||||
) | ) | ||||
// DateLang transforms standard language locale name to corresponding value in datetime plugin. | // DateLang transforms standard language locale name to corresponding value in datetime plugin. | ||||
@@ -1182,6 +1186,10 @@ func NewContext() { | |||||
ModelArtsUsername = sec.Key("USERNAME").MustString("") | ModelArtsUsername = sec.Key("USERNAME").MustString("") | ||||
ModelArtsPassword = sec.Key("PASSWORD").MustString("") | ModelArtsPassword = sec.Key("PASSWORD").MustString("") | ||||
ModelArtsDomain = sec.Key("DOMAIN").MustString("cn-south-222") | ModelArtsDomain = sec.Key("DOMAIN").MustString("cn-south-222") | ||||
ProfileID = sec.Key("PROFILE_ID").MustString("") | |||||
PoolInfos = sec.Key("POOL_INFOS").MustString("") | |||||
Flavor = sec.Key("FLAVOR").MustString("") | |||||
FlavorInfos = sec.Key("FLAVOR_INFOS").MustString("") | |||||
} | } | ||||
func loadInternalToken(sec *ini.Section) string { | func loadInternalToken(sec *ini.Section) string { | ||||
@@ -483,16 +483,25 @@ func GetSuccessChunks(ctx *context.Context) { | |||||
if typeCloudBrain == models.TypeCloudBrainOne { | if typeCloudBrain == models.TypeCloudBrainOne { | ||||
chunks, err = storage.GetPartInfos(fileChunk.UUID, fileChunk.UploadID) | chunks, err = storage.GetPartInfos(fileChunk.UUID, fileChunk.UploadID) | ||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetPartInfos failed", err) | |||||
return | |||||
log.Error("GetPartInfos failed:%v", err.Error()) | |||||
} | } | ||||
} else { | } else { | ||||
chunks, err = storage.GetObsPartInfos(fileChunk.UUID, fileChunk.UploadID) | chunks, err = storage.GetObsPartInfos(fileChunk.UUID, fileChunk.UploadID) | ||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetObsPartInfos failed", err) | |||||
return | |||||
log.Error("GetObsPartInfos failed:%v", err.Error()) | |||||
} | } | ||||
} | } | ||||
if err != nil { | |||||
models.DeleteFileChunk(fileChunk) | |||||
ctx.JSON(200, map[string]string{ | |||||
"uuid": "", | |||||
"uploaded": "0", | |||||
"uploadID": "", | |||||
"chunks": "", | |||||
}) | |||||
return | |||||
} | |||||
} | } | ||||
var attachID int64 | var attachID int64 | ||||
@@ -90,13 +90,12 @@ func cutString(str string, lens int) string { | |||||
func jobNamePrefixValid(s string) string { | func jobNamePrefixValid(s string) string { | ||||
lowStr := strings.ToLower(s) | lowStr := strings.ToLower(s) | ||||
re := regexp.MustCompile(`[^a-z0-9\\.\\-]+`) | |||||
re := regexp.MustCompile(`[^a-z0-9_\\-]+`) | |||||
return re.ReplaceAllString(lowStr, "") | return re.ReplaceAllString(lowStr, "") | ||||
} | } | ||||
func CloudBrainNew(ctx *context.Context) { | |||||
func cloudBrainNewDataPrepare(ctx *context.Context) error{ | |||||
ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
t := time.Now() | t := time.Now() | ||||
var jobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | var jobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | ||||
ctx.Data["job_name"] = jobName | ctx.Data["job_name"] = jobName | ||||
@@ -104,7 +103,7 @@ func CloudBrainNew(ctx *context.Context) { | |||||
result, err := cloudbrain.GetImages() | result, err := cloudbrain.GetImages() | ||||
if err != nil { | if err != nil { | ||||
ctx.Data["error"] = err.Error() | ctx.Data["error"] = err.Error() | ||||
log.Error("cloudbrain.GetImages failed:", err.Error(), ctx.Data["msgID"]) | |||||
log.Error("cloudbrain.GetImages failed:", err.Error(), ctx.Data["MsgID"]) | |||||
} | } | ||||
for i, payload := range result.Payload.ImageInfo { | for i, payload := range result.Payload.ImageInfo { | ||||
@@ -120,7 +119,7 @@ func CloudBrainNew(ctx *context.Context) { | |||||
resultPublic, err := cloudbrain.GetPublicImages() | resultPublic, err := cloudbrain.GetPublicImages() | ||||
if err != nil { | if err != nil { | ||||
ctx.Data["error"] = err.Error() | ctx.Data["error"] = err.Error() | ||||
log.Error("cloudbrain.GetPublicImages failed:", err.Error(), ctx.Data["msgID"]) | |||||
log.Error("cloudbrain.GetPublicImages failed:", err.Error(), ctx.Data["MsgID"]) | |||||
} | } | ||||
for i, payload := range resultPublic.Payload.ImageInfo { | for i, payload := range resultPublic.Payload.ImageInfo { | ||||
@@ -135,8 +134,8 @@ func CloudBrainNew(ctx *context.Context) { | |||||
attachs, err := models.GetAllUserAttachments(ctx.User.ID) | attachs, err := models.GetAllUserAttachments(ctx.User.ID) | ||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetAllUserAttachments failed:", err) | |||||
return | |||||
log.Error("GetAllUserAttachments failed: %v", err, ctx.Data["MsgID"]) | |||||
return err | |||||
} | } | ||||
ctx.Data["attachments"] = attachs | ctx.Data["attachments"] = attachs | ||||
@@ -163,6 +162,16 @@ func CloudBrainNew(ctx *context.Context) { | |||||
ctx.Data["resource_specs"] = cloudbrain.ResourceSpecs.ResourceSpec | ctx.Data["resource_specs"] = cloudbrain.ResourceSpecs.ResourceSpec | ||||
ctx.Data["snn4imagenet_path"] = cloudbrain.Snn4imagenetMountPath | ctx.Data["snn4imagenet_path"] = cloudbrain.Snn4imagenetMountPath | ||||
ctx.Data["is_snn4imagenet_enabled"] = setting.IsSnn4imagenetEnabled | ctx.Data["is_snn4imagenet_enabled"] = setting.IsSnn4imagenetEnabled | ||||
return nil | |||||
} | |||||
func CloudBrainNew(ctx *context.Context) { | |||||
err := cloudBrainNewDataPrepare(ctx) | |||||
if err != nil { | |||||
ctx.ServerError("get new cloudbrain info failed", err) | |||||
return | |||||
} | |||||
ctx.HTML(200, tplCloudBrainNew) | ctx.HTML(200, tplCloudBrainNew) | ||||
} | } | ||||
@@ -178,7 +187,8 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
resourceSpecId := form.ResourceSpecId | resourceSpecId := form.ResourceSpecId | ||||
if jobType != string(models.JobTypeBenchmark) && jobType != string(models.JobTypeDebug) && jobType != string(models.JobTypeSnn4imagenet) { | if jobType != string(models.JobTypeBenchmark) && jobType != string(models.JobTypeDebug) && jobType != string(models.JobTypeSnn4imagenet) { | ||||
log.Error("jobtype error:", jobType, ctx.Data["msgID"]) | |||||
log.Error("jobtype error:", jobType, ctx.Data["MsgID"]) | |||||
cloudBrainNewDataPrepare(ctx) | |||||
ctx.RenderWithErr("jobtype error", tplCloudBrainNew, &form) | ctx.RenderWithErr("jobtype error", tplCloudBrainNew, &form) | ||||
return | return | ||||
} | } | ||||
@@ -186,11 +196,13 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
_, err := models.GetCloudbrainByName(jobName) | _, err := models.GetCloudbrainByName(jobName) | ||||
if err == nil { | if err == nil { | ||||
log.Error("the job name did already exist", ctx.Data["MsgID"]) | log.Error("the job name did already exist", ctx.Data["MsgID"]) | ||||
cloudBrainNewDataPrepare(ctx) | |||||
ctx.RenderWithErr("the job name did already exist", tplCloudBrainNew, &form) | ctx.RenderWithErr("the job name did already exist", tplCloudBrainNew, &form) | ||||
return | return | ||||
} else { | } else { | ||||
if !models.IsErrJobNotExist(err) { | if !models.IsErrJobNotExist(err) { | ||||
log.Error("system error, %v", err, ctx.Data["MsgID"]) | log.Error("system error, %v", err, ctx.Data["MsgID"]) | ||||
cloudBrainNewDataPrepare(ctx) | |||||
ctx.RenderWithErr("system error", tplCloudBrainNew, &form) | ctx.RenderWithErr("system error", tplCloudBrainNew, &form) | ||||
return | return | ||||
} | } | ||||
@@ -201,6 +213,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath | modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath | ||||
err = os.MkdirAll(modelPath, os.ModePerm) | err = os.MkdirAll(modelPath, os.ModePerm) | ||||
if err != nil { | if err != nil { | ||||
cloudBrainNewDataPrepare(ctx) | |||||
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) | ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) | ||||
return | return | ||||
} | } | ||||
@@ -224,6 +237,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, jobType, gpuQueue, resourceSpecId) | err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, jobType, gpuQueue, resourceSpecId) | ||||
if err != nil { | if err != nil { | ||||
cloudBrainNewDataPrepare(ctx) | |||||
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) | ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) | ||||
return | return | ||||
} | } | ||||
@@ -2,6 +2,7 @@ package repo | |||||
import ( | import ( | ||||
"code.gitea.io/gitea/modules/modelarts" | "code.gitea.io/gitea/modules/modelarts" | ||||
"encoding/json" | |||||
"errors" | "errors" | ||||
"github.com/unknwon/com" | "github.com/unknwon/com" | ||||
"strconv" | "strconv" | ||||
@@ -84,7 +85,10 @@ func ModelArtsNew(ctx *context.Context) { | |||||
ctx.Data["dataset_path"] = modelarts.DataSetMountPath | ctx.Data["dataset_path"] = modelarts.DataSetMountPath | ||||
ctx.Data["env"] = modelarts.NotebookEnv | ctx.Data["env"] = modelarts.NotebookEnv | ||||
ctx.Data["notebook_type"] = modelarts.NotebookType | ctx.Data["notebook_type"] = modelarts.NotebookType | ||||
ctx.Data["flavor"] = modelarts.FlavorInfo | |||||
if modelarts.FlavorInfos == nil { | |||||
json.Unmarshal([]byte(setting.FlavorInfos), &modelarts.FlavorInfos) | |||||
} | |||||
ctx.Data["flavors"] = modelarts.FlavorInfos.FlavorInfo | |||||
ctx.HTML(200, tplModelArtsNew) | ctx.HTML(200, tplModelArtsNew) | ||||
} | } | ||||
@@ -59,7 +59,7 @@ func SendTestMail(email string) error { | |||||
func SendUserMail(language string, u *models.User, tpl base.TplName, code, subject, info string) { | func SendUserMail(language string, u *models.User, tpl base.TplName, code, subject, info string) { | ||||
data := map[string]interface{}{ | data := map[string]interface{}{ | ||||
"DisplayName": u.DisplayName(), | "DisplayName": u.DisplayName(), | ||||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, language), | |||||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, "en-US"), | |||||
"ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, language), | "ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, language), | ||||
"Code": code, | "Code": code, | ||||
} | } | ||||
@@ -97,7 +97,7 @@ func SendResetPasswordMail(locale Locale, u *models.User) { | |||||
func SendActivateEmailMail(locale Locale, u *models.User, email *models.EmailAddress) { | func SendActivateEmailMail(locale Locale, u *models.User, email *models.EmailAddress) { | ||||
data := map[string]interface{}{ | data := map[string]interface{}{ | ||||
"DisplayName": u.DisplayName(), | "DisplayName": u.DisplayName(), | ||||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale.Language()), | |||||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, "en-US"), | |||||
"Code": u.GenerateEmailActivateCode(email.Email), | "Code": u.GenerateEmailActivateCode(email.Email), | ||||
"Email": email.Email, | "Email": email.Email, | ||||
} | } | ||||
@@ -132,7 +132,12 @@ | |||||
</div> | </div> | ||||
<div class="inline required field"> | <div class="inline required field"> | ||||
<label>规格</label> | <label>规格</label> | ||||
<input name="flavor" id="cloudbrain_flavor" value="{{.flavor}}" tabindex="3" autofocus required maxlength="255" readonly="readonly"> | |||||
<select id="cloudbrain_flavor" class="ui search dropdown" placeholder="选择规格" style='width:385px' name="flavor"> | |||||
{{range .flavors}} | |||||
<option name="flavor" value="{{.Value}}">{{.Value}}</option> | |||||
{{end}} | |||||
</select> | |||||
</div> | </div> | ||||
<div class="inline required field"> | <div class="inline required field"> | ||||
<label>数据集存放路径</label> | <label>数据集存放路径</label> | ||||