#107 #92, #62, #27, #12, #11

Merged
liwei03 merged 6 commits from openioctopus/octopus:master into master 2 years ago
  1. +9
    -0
      admin-portal/src/api/modelDev.js
  2. +8
    -0
      admin-portal/src/api/trainingManager.js
  3. +58
    -0
      admin-portal/src/views/devManager/components/notebook/detailDialog.vue
  4. +139
    -0
      admin-portal/src/views/devManager/components/notebook/notebookInfo.vue
  5. +45
    -6
      admin-portal/src/views/devManager/components/notebook/notebookList.vue
  6. +108
    -0
      admin-portal/src/views/devManager/components/notebook/notebookProfile.vue
  7. +146
    -29
      admin-portal/src/views/traningManager/components/taskInfo.vue
  8. +58
    -0
      openai-portal/src/views/modelDev/components/notebook/detailDialog.vue
  9. +29
    -12
      openai-portal/src/views/modelDev/components/notebook/notebookInfo.vue
  10. +13
    -13
      openai-portal/src/views/modelDev/components/notebook/notebookList.vue
  11. +108
    -0
      openai-portal/src/views/modelDev/components/notebook/notebookProfile.vue
  12. +37
    -0
      server/admin-server/api/v1/develop.proto
  13. +38
    -0
      server/admin-server/api/v1/trainJob.proto
  14. +22
    -0
      server/admin-server/internal/service/develop.go
  15. +21
    -0
      server/admin-server/internal/service/trainjob.go

+ 9
- 0
admin-portal/src/api/modelDev.js View File

@@ -24,6 +24,15 @@ export async function getNotebookList(payload) {
return res
}

export async function getNotebookInfo(params) {
const res = await request({
url: `/v1/developmanage/notebookevent`,
method: 'get',
params
})
return res
}

export async function stopNotebook(id) {
const res = await request({
url: `/v1/developmanage/notebook/${id}/stop`,


+ 8
- 0
admin-portal/src/api/trainingManager.js View File

@@ -36,4 +36,12 @@ export function downloadLog(params) {
method: 'get'
})
}
// 训任务运行信息
export function getTempalteInfo(params) {
return request({
url: `/v1/trainmanage/trainjobevent`,
method: 'get',
params
})
}


+ 58
- 0
admin-portal/src/views/devManager/components/notebook/detailDialog.vue View File

@@ -0,0 +1,58 @@
v<template>
<div>
<el-dialog
title="详情"
width="80%"
:visible.sync="CreateFormVisible"
:before-close="handleDialogClose"
:append-to-body="true"
custom-class="dialog"
:close-on-click-modal="false"
>
<el-tabs>
<el-tab-pane label="运行简况">
<notebookProfile :notebook-data="notebookData" />
</el-tab-pane>
<el-tab-pane label="运行信息">
<notebookInfo :notebook-data="notebookData" />
</el-tab-pane>
</el-tabs>
</el-dialog>
</div>
</template>
<script>
import notebookInfo from "./notebookInfo.vue"
import notebookProfile from "./notebookProfile.vue"
export default {
name: "DetailDialog",
props: {
detailData: {
type: Object,
default: () => {}
}
},
components: {
notebookInfo,
notebookProfile
},
data() {
return {
CreateFormVisible: true,
notebookData: {},
}
},
created() {
this.notebookData = this.detailData
},
methods: {
handleDialogClose() {
this.$emit('close', false)
}
}
}
</script>
<style lang="scss">
.dialog {
min-height: 800px
}
</style>

+ 139
- 0
admin-portal/src/views/devManager/components/notebook/notebookInfo.vue View File

@@ -0,0 +1,139 @@
<template>
<div>
<div>
<el-row>
<el-col :span="12">
<div>任务名称:<span>{{ notebookInfo.name }}</span></div>
</el-col>
<el-col :span="12">
<div>是否分布式:<span>否</span></div>
</el-col>
</el-row>
<el-input
v-if="showInfo"
v-model="subTaskInfo"
type="textarea"
:readonly="true"
:rows="20"
/>
</div>

<div class="block">
<el-pagination
v-if="showInfo"
:current-page="pageIndex"
:page-sizes="[10, 20, 50, 80]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>

<div slot="footer" class="dialog-footer" />
</div>
</template>

<script>
import { getNotebookInfo } from "@/api/modelDev";
export default {
name: "NotebookInfo",
props: {
notebookData: {
type: Object,
default: () => {}
}
},
data() {
return {
notebookInfo: {},
showInfo: false,
infoVisible: true,
subTaskInfo: "",
total: 0,
pageIndex: 1,
pageSize: 10,
taskIndex: 1,
replicaIndex: 1
}
},
created() {
this.notebookInfo = this.notebookData
this.getNotebookInfo()
},
methods: {
getNotebookInfo(){
const param = {
id: this.notebookInfo.notebookJobId,
pageIndex: this.pageIndex,
pageSize: this.pageSize,
taskIndex: this.taskIndex,
replicaIndex: this.replicaIndex
}
getNotebookInfo(param).then(response => {
if (!response.success) {
this.$message({
message: "暂无相关运行信息",
type: 'warning'
});
return
}

this.showInfo = response.payload.notebookEvents.length
this.total = response.payload.totalSize

let infoMessage = ""

response.payload.notebookEvents.forEach(function(element) {
const title = element.reason
const message = element.message
infoMessage += "\n" + "[" + title + "]"
infoMessage += "\n" + "[" + message + "]" + "\n"
})

this.subTaskInfo = infoMessage
}).catch(err => {
console.log("err:", err)
this.$message({
message: "未知错误",
type: 'warning'
});
});
},
handleDialogClose() {
this.$emit('close', false)
},
handleSizeChange(val) {
this.pageSize = val
this.getNotebookInfo()
},
handleCurrentChange(val) {
this.pageIndex = val
this.getNotebookInfo()
}
},
}
</script>

<style lang="scss" scoped>
.el-col {
margin: 10px 0 20px 0;
font-size: 15px;
font-weight: 800;

span {
font-weight: 400;
margin-left: 20px
}
}

// .select {
// margin-left: 5px;
// }

.block {
float: right;
margin: 20px;
}
</style>

+ 45
- 6
admin-portal/src/views/devManager/components/notebook/notebookList.vue View File

@@ -52,14 +52,33 @@
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<div v-if="({'running':true,'pending':true,'preparing':true})[scope.row.status] || false">
<el-button slot="reference" type="text" @click="confirmStop(scope.row)">停止</el-button>
</div>
<div v-if="({'stopped':true})[scope.row.status] || false">
</div>
<!-- <div v-if="({'running':true,'pending':true,'preparing':true})[scope.row.status] || false"> -->
<el-button
v-if="({'running':true,'pending':true,'preparing':true})[scope.row.status] || false"
slot="reference"
type="text"
@click="confirmStop(scope.row)"
>
停止
</el-button>
<!-- </div> -->
<!-- <div v-if="({'stopped':true})[scope.row.status] || false">
</div> -->
<el-button slot="reference" type="text" @click="showNotebookInfo(scope.row)">
详情
</el-button>
</template>
</el-table-column>
</el-table>

<detailDialog
v-if="detailVisible"
:detail-data="detailData"
@confirm="confirm"
@cancel="cancel"
@close="close"
/>

<div class="block">
<el-pagination
:current-page="searchData.pageIndex"
@@ -75,6 +94,7 @@
</template>

<script>
import detailDialog from "./detailDialog.vue"
import searchForm from '@/components/search/index.vue'
import { getNotebookList, stopNotebook } from "@/api/modelDev"
import { parseTime } from '@/utils/index'
@@ -82,10 +102,13 @@ import { getErrorMsg } from '@/error/index'
export default {
name: "NotebookList",
components: {
searchForm
searchForm,
detailDialog
},
data() {
return {
detailData: {},
detailVisible: false,
row: {},
total: undefined,
notebookList: [],
@@ -170,6 +193,10 @@ export default {
});
});
},
showNotebookInfo(row) {
this.detailVisible = true
this.detailData = row
},
handleStop(row) {
stopNotebook(row.id).then(response => {
if (response.success) {
@@ -183,6 +210,18 @@ export default {
}
})
},
close(val) {
this.detailVisible = val;
this.getNotebookList(this.searchData);
},
cancel(val) {
this.detailVisible = val;
this.getNotebookList(this.searchData);
},
confirm(val) {
this.detailVisible = val;
this.getNotebookList(this.searchData);
},
// 时间戳转换日期
parseTime(val) {
return parseTime(val)


+ 108
- 0
admin-portal/src/views/devManager/components/notebook/notebookProfile.vue View File

@@ -0,0 +1,108 @@
<template>
<div>
<el-row>
<el-col :span="12">
<div>
任务名称:
<span>{{ profileInfo.name }}</span>
</div>
</el-col>
<el-col :span="12">
<div>
描述:
<span>{{ profileInfo.desc }}</span>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div>
选用算法:
<span>{{ profileInfo.algorithmName }}</span>
</div>
</el-col>
<el-col :span="12">
<div>
镜像选择:
<span>{{ profileInfo.imageName }}</span>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div>
选用数据集:
<span>{{ profileInfo.datasetName }}</span>
</div>
</el-col>
<el-col :span="12">
<div>
是否分布式:
<span>否</span>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div>
资源规格:
<span>{{ profileInfo.resourceSpecName }}</span>
</div>
</el-col>
<el-col :span="12">
<div>
任务状态:
<span>{{ statusText[profileInfo.status][1] }}</span>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
name: "NotebookProfile",
props: {
notebookData: {
type: Object,
default: () => {}
}
},
data() {
return {
profileInfo: {},
statusText: {
'preparing': ['status-ready', '初始中'],
'pending': ['status-agent', '等待中'],
'running': ['status-running', '运行中'],
'failed': ['status-danger', '失败'],
'succeeded': ['status-success', '成功'],
'stopped': ['status-stopping', '已停止']
}
}
},
created() {
this.profileInfo = this.notebookData
}
}
</script>
<style lang="scss" scoped>
.el-col {
margin: 10px 0 20px 0;
font-size: 15px;
font-weight: 800;

span {
font-weight: 400;
margin-left: 20px
}
}

// .taskList {
// font-weight: 800;
// }

.block {
float: right;
margin: 20px;
}
</style>

+ 146
- 29
admin-portal/src/views/traningManager/components/taskInfo.vue View File

@@ -1,10 +1,65 @@
<template>
<div>
<div v-html="initInfo"></div>
<el-row>
<el-col :span="12">
<div>任务名称:<span>{{ data.name }}</span></div>
</el-col>
<el-col :span="12">
<div>是否分布式:<span>{{ data.isDistributed?'是':'否' }}</span></div>
</el-col>
</el-row>
<el-row>
<el-col v-if="data.isDistributed" :span="12">
<el-form ref="ruleForm" :model="ruleForm">
<el-form-item prop="subTaskItem">
<div style="font-size: 15px">子任务名:
<el-select
v-model="ruleForm.subTaskItem"
value-key="label"
placeholder="请选择"
@change="selectedSubTaskOption"
>
<el-option
v-for="item in subTaskOptions"
:key="item.label"
:label="item.label"
:value="item"
/>
</el-select>
</div>
</el-form-item>
</el-form>
</el-col>
</el-row>

<div>
<el-row>
<el-input
v-model="subTaskInfo"
type="textarea"
:readonly="true"
:rows="20"
/>
</el-row>
</div>

<div class="block">
<el-pagination
v-if="showInfo"
:current-page="pageIndex"
:page-sizes="[10, 20, 50, 80]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</template>

<script>
import { getTempalteInfo } from '@/api/trainingManager'
export default {
name: "TaskInfo",
props: {
@@ -14,39 +69,101 @@
}
},
data() {
return {
initInfo: ""
}
return {
data: {},
initInfo: "",
subTaskOptions: [],
ruleForm: {
subTaskItem: ""
},
subTaskInfo: "",
pageIndex: 1,
pageSize: 10,
total: 0,
showInfo: false
}
},
created() {
const taskInfoString = this.row.initInfo ? this.row.initInfo.replace(/\n/g, "<br>") : ''
const taskInfoData = JSON.parse(taskInfoString)
for (const pid in taskInfoData['podEvents']) {
const eventList = taskInfoData['podEvents'][pid]
const roleName = taskInfoData['podRoleName'][pid]
if (roleName == "") {
continue
this.data = JSON.parse(JSON.stringify(this.row))
for (let i = 0; i < this.row.config.length; i++) {
for (let j = 0; j < this.row.config[i].taskNumber; j++) {
this.subTaskOptions.push({
label: this.row.config[i].replicaStates[j].key,
taskIndex: i + 1,
replicaIndex: j + 1
})
}
let message = ""
for (const key in eventList) {
const event = eventList[key]
if (event['reason'] == "" && event['message'] == "") {
continue
}
message += "[" + event['reason'] + "]" + "<br>"
message += event['message'] + "<br><br>"
}
if (!this.data.isDistributed) {
this.isDistributed = !this.data.isDistributed
this.selectedSubTaskOption()
}
},
methods: {
selectedSubTaskOption() {
const param = {
id: this.row.id,
pageIndex: this.pageIndex,
pageSize: this.pageSize,
taskIndex: this.ruleForm.subTaskItem.taskIndex?this.ruleForm.subTaskItem.taskIndex:1,
replicaIndex: this.ruleForm.subTaskItem.replicaIndex?this.ruleForm.subTaskItem.replicaIndex:1
}
for (const key in taskInfoData['extras']) {
const event = taskInfoData['extras'][key]
if (event['reason'] == "" && event['message'] == "") {
continue
getTempalteInfo(param).then(response => {
if (response.success) {
this.showInfo = response.payload.jobEvents.length
this.total = response.payload.totalSize
let infoMessage = ""
response.payload.jobEvents.forEach(function(element) {
const title = element.reason
const message = element.message
infoMessage += "\n" + "[" + title + "]"
infoMessage += "\n" + "[" + message + "]" + "\n"
})
this.subTaskInfo = infoMessage
} else {
this.$message({
message: "暂无相关运行信息",
type: 'warning'
});
}
message += "[" + event['reason'] + "]" + "<br>"
message += event['message'] + "<br><br>"
}
message += "<br>"
this.initInfo = message
}).catch(err => {
console.log("err:", err)
this.$message({
message: "未知错误",
type: 'warning'
});
});
},
handleSizeChange(val) {
this.pageSize = val
this.selectedSubTaskOption()
},
handleCurrentChange(val) {
this.pageIndex = val
this.selectedSubTaskOption()
}
}
}
</script>
</script>

<style lang="scss" scoped>
.el-col {
margin: 10px 0 20px 0;
font-size: 15px;
font-weight: 800;

span {
font-weight: 400;
margin-left: 20px
}
}

.select {
margin-left: 5px;
}

.block {
float: right;
margin: 20px;
}
</style>

+ 58
- 0
openai-portal/src/views/modelDev/components/notebook/detailDialog.vue View File

@@ -0,0 +1,58 @@
<template>
<div>
<el-dialog
title="详情"
width="80%"
:visible.sync="CreateFormVisible"
:before-close="handleDialogClose"
:append-to-body="true"
custom-class="dialog"
:close-on-click-modal="false"
>
<el-tabs>
<el-tab-pane label="运行简况">
<notebookProfile :notebook-data="notebookData" />
</el-tab-pane>
<el-tab-pane label="运行信息">
<notebookInfo :notebook-data="notebookData" />
</el-tab-pane>
</el-tabs>
</el-dialog>
</div>
</template>
<script>
import notebookInfo from "./notebookInfo.vue"
import notebookProfile from "./notebookProfile.vue"
export default {
name: "DetailDialog",
components: {
notebookInfo,
notebookProfile
},
props: {
detailData: {
type: Object,
default: () => {}
}
},
data() {
return {
CreateFormVisible: true,
notebookData: {}
}
},
created() {
this.notebookData = this.detailData
},
methods: {
handleDialogClose() {
this.$emit('close', false)
}
}
}
</script>
<style lang="scss">
.dialog {
min-height: 800px
}
</style>

+ 29
- 12
openai-portal/src/views/modelDev/components/notebook/notebookInfo.vue View File

@@ -1,19 +1,20 @@
<template>
<div>
<el-dialog
title="启动信息"
width="80%"
:visible.sync="infoVisible"
:before-close="handleDialogClose"
:close-on-click-modal="false"
>
<div>
<el-row>
<el-col :span="12">
<div>任务名称:<span>{{ notebookInfo.name }}</span></div>
</el-col>
<el-col :span="12">
<div>是否分布式:<span>否</span></div>
</el-col>
</el-row>
<el-input
v-if="showInfo"
v-model="subTaskInfo"
type="textarea"
:readonly="true"
:autosize="true"
:rows="20"
/>
</div>

@@ -31,7 +32,6 @@
</div>

<div slot="footer" class="dialog-footer" />
</el-dialog>
</div>
</template>

@@ -47,6 +47,7 @@ export default {
},
data() {
return {
notebookInfo: {},
showInfo: false,
infoVisible: true,
subTaskInfo: "",
@@ -58,12 +59,13 @@ export default {
}
},
created() {
this.notebookInfo = this.notebookData
this.getNotebookInfo()
},
methods: {
getNotebookInfo(){
getNotebookInfo() {
const param = {
id: this.notebookData.notebookJobId,
id: this.notebookInfo.notebookJobId,
pageIndex: this.pageIndex,
pageSize: this.pageSize,
taskIndex: this.taskIndex,
@@ -110,11 +112,26 @@ export default {
this.pageIndex = val
this.getNotebookInfo()
}
},
}
}
</script>

<style lang="scss" scoped>
.el-col {
margin: 10px 0 20px 0;
font-size: 15px;
font-weight: 800;

span {
font-weight: 400;
margin-left: 20px
}
}

// .select {
// margin-left: 5px;
// }

.block {
float: right;
margin: 20px;


+ 13
- 13
openai-portal/src/views/modelDev/components/notebook/notebookList.vue View File

@@ -74,7 +74,7 @@
停止
</el-button>
<el-button slot="reference" type="text" @click="showNotebookInfo(scope.row)">
信息
详情
</el-button>
</template>
</el-table-column>
@@ -91,9 +91,9 @@
/>
</div>

<notebookInfo
v-if="notebookInfoVisible"
:notebook-data="notebookData"
<detailDialog
v-if="detailVisible"
:detail-data="detailData"
@confirm="confirm"
@cancel="cancel"
@close="close"
@@ -104,7 +104,7 @@

<script>
import notebookCreation from "./notebookCreation.vue"
import notebookInfo from "./notebookInfo.vue"
import detailDialog from "./detailDialog.vue"
import searchForm from '@/components/search/index.vue'
import { getNotebookList, stopNotebook, deleteNotebook, startNotebook } from "@/api/modelDev";
import { parseTime } from '@/utils/index'
@@ -114,7 +114,7 @@
name: "NotebookList",
components: {
notebookCreation,
notebookInfo,
detailDialog,
searchForm
},
props: {
@@ -126,9 +126,9 @@
data() {
return {
row: {},
notebookData: {},
detailData: {},
notebookVisible: false,
notebookInfoVisible: false,
detailVisible: false,
total: undefined,
notebookList: [],
searchForm: [
@@ -278,8 +278,8 @@
});
},
showNotebookInfo(row) {
this.notebookInfoVisible = true
this.notebookData = row
this.detailVisible = true
this.detailData = row
},
handleStop(row) {
stopNotebook(row.id).then(response => {
@@ -331,17 +331,17 @@
},
close(val) {
this.notebookVisible = val;
this.notebookInfoVisible = val;
this.detailVisible = val;
this.getNotebookList(this.searchData);
},
cancel(val) {
this.notebookVisible = val;
this.notebookInfoVisible = val;
this.detailVisible = val;
this.getNotebookList(this.searchData);
},
confirm(val) {
this.notebookVisible = val
this.notebookInfoVisible = val;
this.detailVisible = val;
this.getNotebookList(this.searchData);
}
}


+ 108
- 0
openai-portal/src/views/modelDev/components/notebook/notebookProfile.vue View File

@@ -0,0 +1,108 @@
<template>
<div>
<el-row>
<el-col :span="12">
<div>
任务名称:
<span>{{ profileInfo.name }}</span>
</div>
</el-col>
<el-col :span="12">
<div>
描述:
<span>{{ profileInfo.desc }}</span>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div>
选用算法:
<span>{{ profileInfo.algorithmName }}</span>
</div>
</el-col>
<el-col :span="12">
<div>
镜像选择:
<span>{{ profileInfo.imageName }}</span>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div>
选用数据集:
<span>{{ profileInfo.datasetName }}</span>
</div>
</el-col>
<el-col :span="12">
<div>
是否分布式:
<span>否</span>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div>
资源规格:
<span>{{ profileInfo.resourceSpecName }}</span>
</div>
</el-col>
<el-col :span="12">
<div>
任务状态:
<span>{{ statusText[profileInfo.status][1] }}</span>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
name: "NotebookProfile",
props: {
notebookData: {
type: Object,
default: () => {}
}
},
data() {
return {
profileInfo: {},
statusText: {
'preparing': ['status-ready', '初始中'],
'pending': ['status-agent', '等待中'],
'running': ['status-running', '运行中'],
'failed': ['status-danger', '失败'],
'succeeded': ['status-success', '成功'],
'stopped': ['status-stopping', '已停止']
}
}
},
created() {
this.profileInfo = this.notebookData
}
}
</script>
<style lang="scss" scoped>
.el-col {
margin: 10px 0 20px 0;
font-size: 15px;
font-weight: 800;

span {
font-weight: 400;
margin-left: 20px
}
}

// .taskList {
// font-weight: 800;
// }

.block {
float: right;
margin: 20px;
}
</style>

+ 37
- 0
server/admin-server/api/v1/develop.proto View File

@@ -22,6 +22,12 @@ service Develop {
get: "/v1/developmanage/notebook"
};
};
// 获取Notebook事件列表
rpc GetNotebookEventList (NotebookEventListRequest) returns (NotebookEventListReply) {
option (google.api.http) = {
get: "/v1/developmanage/notebookevent"
};
};
}

message StopNotebookRequest {
@@ -72,4 +78,35 @@ message Notebook {
message ListNotebookReply {
int64 totalSize = 1;
repeated Notebook notebooks = 2;
}

message NotebookEventListRequest {
// 页码,从1开始
int64 pageIndex = 1[(validate.rules).int64 = {gte:1}];
// 页大小,最小1条,最大100条
int64 pageSize = 2[(validate.rules).int64 = {gte:1,lt:100}];
//任务ID
string id = 3[(validate.rules).string = {min_len: 1}];
//子任务序号,从1开始
int64 taskIndex = 4[(validate.rules).int64 = {gte:1,lt:100}];
//副本序号,从1开始
int64 replicaIndex = 5[(validate.rules).int64 = {gte:1,lt:100}];
}

message NotebookEventListReply {
//查询结果总数
int64 totalSize = 1;
//任务事件
repeated NotebookEvent notebookEvents = 2;
}

message NotebookEvent{
//发生时间
string timestamp = 1;
//副本名称
string name = 2;
//原因
string reason = 3;
//消息
string message = 4;
}

+ 38
- 0
server/admin-server/api/v1/trainJob.proto View File

@@ -31,6 +31,13 @@ service TrainJobService {
};
};

// 获取训练任务事件列表
rpc GetJobEventList (JobEventListRequest) returns (JobEventListReply) {
option (google.api.http) = {
get: "/v1/trainmanage/trainjobevent"
};
};

}

message Config {
@@ -174,3 +181,34 @@ message TrainJobInfoReply {
//训练任务
TrainJob trainJob = 1;
}

message JobEventListRequest {
// 页码,从1开始
int64 pageIndex = 1[(validate.rules).int64 = {gte:1}];
// 页大小,最小1条,最大100条
int64 pageSize = 2[(validate.rules).int64 = {gte:1,lt:100}];
//任务ID
string id = 3[(validate.rules).string = {min_len: 1}];
//子任务序号,从1开始
int64 taskIndex = 4[(validate.rules).int64 = {gte:1,lt:100}];
//副本序号,从1开始
int64 replicaIndex = 5[(validate.rules).int64 = {gte:1,lt:100}];
}

message JobEventListReply {
//查询结果总数
int64 totalSize = 1;
//任务事件
repeated JobEvent jobEvents = 2;
}

message JobEvent{
//发生时间
string timestamp = 1;
//副本名称
string name = 2;
//原因
string reason = 3;
//消息
string message = 4;
}

+ 22
- 0
server/admin-server/internal/service/develop.go View File

@@ -105,3 +105,25 @@ func (s *DevelopService) assignValue(ctx context.Context, notebooks []*api.Noteb

return nil
}

// Notebook事件列表
func (s *DevelopService) GetNotebookEventList(ctx context.Context, req *api.NotebookEventListRequest) (*api.NotebookEventListReply, error) {

innerReq := &innerapi.NotebookEventListRequest{}
err := copier.Copy(innerReq, req)
if err != nil {
return nil, errors.Errorf(err, errors.ErrorStructCopy)
}

innerReply, err := s.data.DevelopClient.GetNotebookEventList(ctx, innerReq)
if err != nil {
return nil, err
}

reply := &api.NotebookEventListReply{}
err = copier.Copy(reply, innerReply)
if err != nil {
return nil, err
}
return reply, nil
}

+ 21
- 0
server/admin-server/internal/service/trainjob.go View File

@@ -189,3 +189,24 @@ func (s *TrainJobService) assignValue(ctx context.Context, trainJobs []*api.Trai

return nil
}

// 任务事件列表
func (s *TrainJobService) GetJobEventList(ctx context.Context, req *api.JobEventListRequest) (*api.JobEventListReply, error) {
innerReq := &innerapi.JobEventListRequest{}
err := copier.Copy(innerReq, req)
if err != nil {
return nil, errors.Errorf(err, errors.ErrorStructCopy)
}

innerReply, err := s.data.TrainJobClient.GetJobEventList(ctx, innerReq)
if err != nil {
return nil, err
}

reply := &api.JobEventListReply{}
err = copier.Copy(reply, innerReply)
if err != nil {
return nil, err
}
return reply, nil
}

Loading…
Cancel
Save