| @@ -678,6 +678,8 @@ type GetNotebook2Result struct { | |||
| Flavor string `json:"flavor"` | |||
| CreateTime string | |||
| LatestUpdateTime string | |||
| CreateAt int64 `json:"create_at"` //实例创建的时间,UTC毫秒 | |||
| UpdateAt int64 `json:"update_at"` //实例最后更新(不包括保活心跳)的时间,UTC毫秒 | |||
| Image struct { | |||
| Name string `json:"name"` | |||
| Status string `json:"status"` | |||
| @@ -686,11 +688,9 @@ type GetNotebook2Result struct { | |||
| Duration int `json:"duration"` //auto_stop_time s | |||
| } `json:"image"` | |||
| Lease struct { | |||
| CreateTime int64 `json:"create_time"` //实例创建的时间,UTC毫秒 | |||
| BeginTime string | |||
| CreateTime int64 `json:"create_at"` //实例创建的时间,UTC毫秒 | |||
| Duration int64 `json:"duration"` //实例运行时长,以创建时间为起点计算,即“创建时间+duration > 当前时刻”时,系统会自动停止实例 | |||
| UpdateTime int64 `json:"update_time"` //实例最后更新(不包括保活心跳)的时间,UTC毫秒 | |||
| EndTime string | |||
| UpdateTime int64 `json:"update_at"` //实例最后更新(不包括保活心跳)的时间,UTC毫秒 | |||
| } `json:"lease"` //实例自动停止的倒计时信息 | |||
| VolumeRes struct { | |||
| Capacity int `json:"capacity"` | |||
| @@ -31,6 +31,8 @@ const ( | |||
| //notebook 2.0 | |||
| urlNotebook2 = "/notebooks" | |||
| modelartsIllegalToken = "ModelArts.6401" | |||
| ) | |||
| func getRestyClient() *resty.Client { | |||
| @@ -210,6 +212,11 @@ sendjob: | |||
| if len(response.ErrorCode) != 0 { | |||
| log.Error("GetJob failed(%s): %s", response.ErrorCode, response.ErrorMsg) | |||
| if response.ErrorCode == modelartsIllegalToken && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| return &result, fmt.Errorf("GetJob failed(%s): %s", response.ErrorCode, response.ErrorMsg) | |||
| } | |||
| @@ -256,6 +263,50 @@ sendjob: | |||
| return &result, nil | |||
| } | |||
| func ManageNotebook2(jobID string, param models.NotebookAction) (*models.NotebookActionResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var result models.NotebookActionResult | |||
| retry := 0 | |||
| sendjob: | |||
| res, err := client.R(). | |||
| SetHeader("Content-Type", "application/json"). | |||
| SetAuthToken(TOKEN). | |||
| SetResult(&result). | |||
| Post(HOST + "/v1/" + setting.ProjectID + urlNotebook2 + "/" + jobID + "/" + param.Action) | |||
| if err != nil { | |||
| return &result, fmt.Errorf("resty ManageNotebook2: %v", err) | |||
| } | |||
| if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| var response models.NotebookResult | |||
| err = json.Unmarshal(res.Body(), &response) | |||
| if err != nil { | |||
| log.Error("json.Unmarshal failed: %s", err.Error()) | |||
| return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error()) | |||
| } | |||
| if len(response.ErrorCode) != 0 { | |||
| log.Error("ManageNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg) | |||
| if response.ErrorCode == modelartsIllegalToken && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| return &result, fmt.Errorf("ManageNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg) | |||
| } | |||
| return &result, nil | |||
| } | |||
| func DelNotebook(jobID string) (*models.NotebookDelResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| @@ -295,6 +346,50 @@ sendjob: | |||
| return &result, nil | |||
| } | |||
| func DelNotebook2(jobID string) (*models.NotebookDelResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var result models.NotebookDelResult | |||
| retry := 0 | |||
| sendjob: | |||
| res, err := client.R(). | |||
| SetHeader("Content-Type", "application/json"). | |||
| SetAuthToken(TOKEN). | |||
| SetResult(&result). | |||
| Delete(HOST + "/v1/" + setting.ProjectID + urlNotebook2 + "/" + jobID) | |||
| if err != nil { | |||
| return &result, fmt.Errorf("resty DelJob: %v", err) | |||
| } | |||
| if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| var response models.NotebookResult | |||
| err = json.Unmarshal(res.Body(), &response) | |||
| if err != nil { | |||
| log.Error("json.Unmarshal failed: %s", err.Error()) | |||
| return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error()) | |||
| } | |||
| if len(response.ErrorCode) != 0 { | |||
| log.Error("DelNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg) | |||
| if response.ErrorCode == modelartsIllegalToken && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| return &result, fmt.Errorf("DelNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg) | |||
| } | |||
| return &result, nil | |||
| } | |||
| func DelJob(jobID string) (*models.NotebookDelResult, error) { | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| @@ -1010,6 +1105,11 @@ sendjob: | |||
| if response.ErrorCode == errorCodeExceedLimit { | |||
| response.ErrorMsg = "所选规格使用数量已超过最大配额限制。" | |||
| } | |||
| if response.ErrorCode == modelartsIllegalToken && retry < 1 { | |||
| retry++ | |||
| _ = getToken() | |||
| goto sendjob | |||
| } | |||
| return &result, fmt.Errorf("createNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg) | |||
| } | |||
| @@ -512,6 +512,7 @@ var ( | |||
| ProfileID string | |||
| PoolInfos string | |||
| Flavor string | |||
| DebugHost string | |||
| //train-job | |||
| ResourcePools string | |||
| Engines string | |||
| @@ -1325,6 +1326,7 @@ func NewContext() { | |||
| ProfileID = sec.Key("PROFILE_ID").MustString("") | |||
| PoolInfos = sec.Key("POOL_INFOS").MustString("") | |||
| Flavor = sec.Key("FLAVOR").MustString("") | |||
| DebugHost = sec.Key("DEBUG_SERVER_HOST").MustString("http://192.168.202.73") | |||
| ResourcePools = sec.Key("Resource_Pools").MustString("") | |||
| Engines = sec.Key("Engines").MustString("") | |||
| EngineVersions = sec.Key("Engine_Versions").MustString("") | |||
| @@ -25,8 +25,6 @@ import ( | |||
| "code.gitea.io/gitea/modules/obs" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/modules/storage" | |||
| "github.com/unknwon/com" | |||
| ) | |||
| const ( | |||
| @@ -246,10 +244,8 @@ func NotebookShow(ctx *context.Context) { | |||
| return | |||
| } | |||
| createTime, _ := com.StrTo(result.Lease.CreateTime).Int64() | |||
| result.CreateTime = time.Unix(int64(createTime/1000), 0).Format("2006-01-02 15:04:05") | |||
| endTime, _ := com.StrTo(result.Lease.UpdateTime).Int64() | |||
| result.LatestUpdateTime = time.Unix(int64(endTime/1000), 0).Format("2006-01-02 15:04:05") | |||
| result.CreateTime = time.Unix(int64(result.CreateAt/1000), 0).Format("2006-01-02 15:04:05") | |||
| result.LatestUpdateTime = time.Unix(int64(result.UpdateAt/1000), 0).Format("2006-01-02 15:04:05") | |||
| //result.QueuingInfo.BeginTime = time.Unix(int64(result.QueuingInfo.BeginTimestamp/1000), 0).Format("2006-01-02 15:04:05") | |||
| //result.QueuingInfo.EndTime = time.Unix(int64(result.QueuingInfo.EndTimestamp/1000), 0).Format("2006-01-02 15:04:05") | |||
| } | |||
| @@ -287,6 +283,11 @@ func NotebookDebug(ctx *context.Context) { | |||
| ctx.Redirect(debugUrl) | |||
| } | |||
| func NotebookDebug2(ctx *context.Context) { | |||
| debugUrl := setting.DebugHost + "/" + ctx.Cloudbrain.JobID + "/lab" | |||
| ctx.Redirect(debugUrl) | |||
| } | |||
| func NotebookManage(ctx *context.Context) { | |||
| var jobID = ctx.Params(":jobid") | |||
| var action = ctx.Params(":action") | |||
| @@ -358,9 +359,9 @@ func NotebookManage(ctx *context.Context) { | |||
| param := models.NotebookAction{ | |||
| Action: action, | |||
| } | |||
| res, err := modelarts.ManageNotebook(jobID, param) | |||
| res, err := modelarts.ManageNotebook2(jobID, param) | |||
| if err != nil { | |||
| log.Error("ManageNotebook(%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" | |||
| errorMsg = "启动失败" | |||
| break | |||
| @@ -398,10 +399,10 @@ func NotebookDel(ctx *context.Context) { | |||
| return | |||
| } | |||
| _, err := modelarts.DelNotebook(jobID) | |||
| _, err := modelarts.DelNotebook2(jobID) | |||
| if err != nil { | |||
| log.Error("DelJob(%s) failed:%v", task.JobName, err.Error()) | |||
| ctx.ServerError("DelJob failed", err) | |||
| log.Error("DelNotebook2(%s) failed:%v", task.JobName, err.Error()) | |||
| ctx.ServerError("DelNotebook2 failed", err) | |||
| return | |||
| } | |||
| @@ -1041,7 +1041,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| */ | |||
| m.Group("/:jobid", func() { | |||
| m.Get("", reqRepoCloudBrainReader, repo.NotebookShow) | |||
| m.Get("/debug", cloudbrain.AdminOrJobCreaterRight, repo.NotebookDebug) | |||
| m.Get("/debug", cloudbrain.AdminOrJobCreaterRight, repo.NotebookDebug2) | |||
| m.Post("/:action", reqRepoCloudBrainWriter, repo.NotebookManage) | |||
| m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookDel) | |||
| }) | |||
| @@ -47,85 +47,7 @@ | |||
| </table> | |||
| {{end}} | |||
| </div> | |||
| <!--<div class="ui blue segment"> | |||
| {{with .result}} | |||
| <table class="ui celled striped table"> | |||
| <thead> | |||
| <tr> <th colspan="2"> 配置信息 </th> </tr> | |||
| </thead> | |||
| <tbody> | |||
| <tr> | |||
| <td class="four wide"> 开发环境类型 </td> | |||
| <td>{{.Profile.DeType}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 硬件类型 </td> | |||
| <td>{{.Profile.FlavorType}}</td> | |||
| </tr> | |||
| </tbody> | |||
| </table> | |||
| <table class="ui celled striped table"> | |||
| <thead> | |||
| <tr> <th colspan="2"> 机器规格详情 </th> </tr> | |||
| </thead> | |||
| <tbody> | |||
| <tr> | |||
| <td class="four wide"> 机器规格 </td> | |||
| <td> {{.Flavor}} </td> | |||
| </tr> | |||
| <tr> | |||
| <td> 规格名称 </td> | |||
| <td>{{.FlavorDetails.Name}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 规格销售状态 </td> | |||
| <td>{{.FlavorDetails.Status}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 排队个数 </td> | |||
| <td>{{.FlavorDetails.QueuingNum}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 排到队的剩余时间(秒) </td> | |||
| <td>{{.FlavorDetails.QueueLeftTime}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 自动停止时间(秒) </td> | |||
| <td>{{.FlavorDetails.Duration}}</td> | |||
| </tr> | |||
| </tbody> | |||
| </table> | |||
| <table class="ui celled striped table" {{if eq .QueuingInfo.RemainTime 0}}hidden{{end}}> | |||
| <thead> | |||
| <tr> <th colspan="2"> 排队信息 </th> </tr> | |||
| </thead> | |||
| <tbody> | |||
| <tr> | |||
| <td> 实例状态 </td> | |||
| <td>{{.QueuingInfo.Status}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 实例排队的开始时间 </td> | |||
| <td>{{.QueuingInfo.BeginTime}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 排到队的剩余时间(秒) </td> | |||
| <td>{{.QueuingInfo.RemainTime}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 实例排队的预计停止时间 </td> | |||
| <td>{{.QueuingInfo.EndTime}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 实例在队列中的排位 </td> | |||
| <td>{{.QueuingInfo.Rank}}</td> | |||
| </tr> | |||
| </tbody> | |||
| </table> | |||
| {{end}} | |||
| </div>--> | |||
| </div> | |||
| </div> | |||