From 7f204d6b1b0092318a5cb0a8522cc33ecc872e85 Mon Sep 17 00:00:00 2001 From: debuggy Date: Sun, 5 Jul 2020 20:23:14 +0800 Subject: [PATCH 1/6] Add task debug info in webportal --- .../components/task-role-container-list.jsx | 189 ++++++++++++++++-- .../job-detail/components/task-role.jsx | 28 ++- 2 files changed, 198 insertions(+), 19 deletions(-) diff --git a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx index 6679871667..6f82385cbd 100644 --- a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx +++ b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx @@ -25,6 +25,7 @@ import { } from '@uifabric/styling'; import c from 'classnames'; import { capitalize, isEmpty, isNil, flatten } from 'lodash'; +import { DateTime } from 'luxon'; import { CommandBarButton, PrimaryButton, @@ -41,6 +42,7 @@ import { } from 'office-ui-fabric-react/lib/DetailsList'; import PropTypes from 'prop-types'; import React from 'react'; +import yaml from 'js-yaml'; import localCss from './task-role-container-list.scss'; import t from '../../../../../components/tachyons.scss'; @@ -48,7 +50,7 @@ import t from '../../../../../components/tachyons.scss'; import Context from './context'; import Timer from './timer'; import { getContainerLog } from '../conn'; -import { parseGpuAttr } from '../util'; +import { parseGpuAttr, printDateTime } from '../util'; import config from '../../../../../config/webportal.config'; import MonacoPanel from '../../../../../components/monaco-panel'; import StatusBadge from '../../../../../components/status-badge'; @@ -321,25 +323,115 @@ export default class TaskRoleContainerList extends React.Component { } } - getColumns() { - const columns = [ + getColumns(showDebugInfo) { + const optionalColumns = [ { - key: 'number', - name: 'No.', + key: 'nodeName', + name: 'Node Name', headerClassName: FontClassNames.medium, - minWidth: 50, - maxWidth: 50, + minWidth: 100, + maxWidth: 100, isResizable: true, - onRender: (item, idx) => { + onRender: item => { return ( - !isNil(idx) && ( -
{idx}
- ) +
+ {item.podNodeName} +
+ ); + }, + }, + { + key: 'exitCode', + name: 'Exit Code', + headerClassName: FontClassNames.medium, + minWidth: 100, + maxWidth: 100, + isResizable: true, + onRender: item => { + return ( +
+ {item.containerExitCode} +
+ ); + }, + }, + { + key: 'exitType', + name: 'Exit Type', + headerClassName: FontClassNames.medium, + minWidth: 100, + maxWidth: 100, + isResizable: true, + onRender: item => { + return ( +
+ {item.containerExitSpec.type} +
+ ); + }, + }, + { + key: 'exitDiagonostic', + name: 'Exit Diagnostics', + headerClassName: FontClassNames.medium, + minWidth: 200, + maxWidth: 200, + isResizable: true, + onRender: item => { + return ( + { + const result = []; + // exit spec + const spec = item.containerExitSpec; + if (spec) { + // divider + result.push(Array.from({ length: 80 }, () => '-').join('')); + result.push(''); + // content + result.push('[Exit Spec]'); + result.push(''); + result.push(yaml.safeDump(spec)); + result.push(''); + } + + // diagnostics + const diag = item.containerExitDiagnostics; + if (diag) { + // divider + result.push(Array.from({ length: 80 }, () => '-').join('')); + result.push(''); + // content + result.push('[Exit Diagnostics]'); + result.push(''); + result.push(diag); + result.push(''); + } + + this.setState({ + monacoProps: { + language: 'text', + value: result.join('\n'), + options: { + wordWrap: 'off', + readOnly: true, + }, + }, + monacoTitle: `Task Exit Diagonostics`, + }); + }} + /> ); }, }, { - key: 'name', + key: 'containerId', name: 'Container ID', headerClassName: FontClassNames.medium, minWidth: 100, @@ -356,6 +448,51 @@ export default class TaskRoleContainerList extends React.Component { ); }, }, + { + key: 'startTime', + name: 'Start Time', + headerClassName: FontClassNames.medium, + minWidth: 150, + isResizable: true, + onRender: item => { + return ( +
+ {printDateTime(DateTime.fromISO(item.startTime))} +
+ ); + }, + }, + { + key: 'completionTime', + name: 'Completion Time', + headerClassName: FontClassNames.medium, + minWidth: 150, + isResizable: true, + onRender: item => { + return ( +
+ {printDateTime(DateTime.fromISO(item.completionTime))} +
+ ); + }, + }, + ]; + const defaultColumns = [ + { + key: 'number', + name: 'No.', + headerClassName: FontClassNames.medium, + minWidth: 50, + maxWidth: 50, + isResizable: true, + onRender: (item, idx) => { + return ( + !isNil(idx) && ( +
{idx}
+ ) + ); + }, + }, { key: 'ip', name: 'IP', @@ -392,7 +529,7 @@ export default class TaskRoleContainerList extends React.Component { className: FontClassNames.mediumPlus, headerClassName: FontClassNames.medium, minWidth: 120, - maxWidth: 180, + maxWidth: 200, isResizable: true, onRender: item => { const ports = item.containerPorts; @@ -490,6 +627,21 @@ export default class TaskRoleContainerList extends React.Component { isResizable: true, onRender: item => , }, + { + key: 'retryCount', + name: 'Retry Count', + headerClassName: FontClassNames.medium, + minWidth: 100, + maxWidth: 100, + isResizable: true, + onRender: (item, idx) => { + return ( +
+ {item.totalRetriedCount} +
+ ); + }, + }, { key: 'info', name: 'Info', @@ -595,6 +747,11 @@ export default class TaskRoleContainerList extends React.Component { }, ]; + let columns = defaultColumns; + if (showDebugInfo) { + columns = defaultColumns.concat(optionalColumns); + } + return columns; } @@ -613,7 +770,7 @@ export default class TaskRoleContainerList extends React.Component { render() { const { monacoTitle, monacoProps, monacoFooterButton, logUrl } = this.state; - const { className, style, taskInfo } = this.props; + const { className, style, taskInfo, showDebugInfo } = this.props; const status = taskInfo.taskStatuses; return (
{/* right */} -
+ + { + this.setState({ + showDebugInfo: checked, + }); + }} + /> {containerListExpanded ? ( )} -
+ {containerListExpanded && ( - + )} From 46b258e2d59c910b923ffe0bd89ac0943bcd9c9c Mon Sep 17 00:00:00 2001 From: debuggy Date: Mon, 6 Jul 2020 15:30:48 +0800 Subject: [PATCH 2/6] Adjust space --- .../components/task-role-container-list.jsx | 84 +++++++++---------- 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx index 6f82385cbd..266a10ab0a 100644 --- a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx +++ b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx @@ -330,7 +330,6 @@ export default class TaskRoleContainerList extends React.Component { name: 'Node Name', headerClassName: FontClassNames.medium, minWidth: 100, - maxWidth: 100, isResizable: true, onRender: item => { return ( @@ -345,7 +344,6 @@ export default class TaskRoleContainerList extends React.Component { name: 'Exit Code', headerClassName: FontClassNames.medium, minWidth: 100, - maxWidth: 100, isResizable: true, onRender: item => { return ( @@ -359,8 +357,7 @@ export default class TaskRoleContainerList extends React.Component { key: 'exitType', name: 'Exit Type', headerClassName: FontClassNames.medium, - minWidth: 100, - maxWidth: 100, + minWidth: 150, isResizable: true, onRender: item => { return ( @@ -375,7 +372,6 @@ export default class TaskRoleContainerList extends React.Component { name: 'Exit Diagnostics', headerClassName: FontClassNames.medium, minWidth: 200, - maxWidth: 200, isResizable: true, onRender: item => { return ( @@ -434,8 +430,7 @@ export default class TaskRoleContainerList extends React.Component { key: 'containerId', name: 'Container ID', headerClassName: FontClassNames.medium, - minWidth: 100, - maxWidth: 500, + minWidth: 300, isResizable: true, onRender: item => { const id = item.containerId; @@ -448,42 +443,14 @@ export default class TaskRoleContainerList extends React.Component { ); }, }, - { - key: 'startTime', - name: 'Start Time', - headerClassName: FontClassNames.medium, - minWidth: 150, - isResizable: true, - onRender: item => { - return ( -
- {printDateTime(DateTime.fromISO(item.startTime))} -
- ); - }, - }, - { - key: 'completionTime', - name: 'Completion Time', - headerClassName: FontClassNames.medium, - minWidth: 150, - isResizable: true, - onRender: item => { - return ( -
- {printDateTime(DateTime.fromISO(item.completionTime))} -
- ); - }, - }, ]; const defaultColumns = [ { key: 'number', name: 'No.', headerClassName: FontClassNames.medium, - minWidth: 50, - maxWidth: 50, + minWidth: 30, + maxWidth: 30, isResizable: true, onRender: (item, idx) => { return ( @@ -566,8 +533,8 @@ export default class TaskRoleContainerList extends React.Component { name: 'GPUs', className: FontClassNames.mediumPlus, headerClassName: FontClassNames.medium, - minWidth: 40, - maxWidth: 60, + minWidth: 35, + maxWidth: 35, isResizable: true, onRender: item => { const gpuAttr = isNil(item.containerGpus) @@ -623,16 +590,42 @@ export default class TaskRoleContainerList extends React.Component { name: 'Status', headerClassName: FontClassNames.medium, minWidth: 100, - maxWidth: 100, isResizable: true, onRender: item => , }, + { + key: 'startTime', + name: 'Start Time', + headerClassName: FontClassNames.medium, + minWidth: 150, + isResizable: true, + onRender: item => { + return ( +
+ {printDateTime(DateTime.fromISO(item.startTime))} +
+ ); + }, + }, + { + key: 'completionTime', + name: 'Completion Time', + headerClassName: FontClassNames.medium, + minWidth: 150, + isResizable: true, + onRender: item => { + return ( +
+ {printDateTime(DateTime.fromISO(item.completionTime))} +
+ ); + }, + }, { key: 'retryCount', - name: 'Retry Count', + name: 'Retries', headerClassName: FontClassNames.medium, - minWidth: 100, - maxWidth: 100, + minWidth: 50, isResizable: true, onRender: (item, idx) => { return ( @@ -647,8 +640,7 @@ export default class TaskRoleContainerList extends React.Component { name: 'Info', className: localCss.pa0I, headerClassName: FontClassNames.medium, - minWidth: 300, - maxWidth: 340, + minWidth: 330, onRender: item => (
{ this.showSshInfo( item.containerId, From cc668b988368cd89954fac00daa89e6113f7aff6 Mon Sep 17 00:00:00 2001 From: debuggy Date: Mon, 6 Jul 2020 16:24:31 +0800 Subject: [PATCH 3/6] update --- .../components/task-role-container-list.jsx | 69 ++++++++++--------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx index 266a10ab0a..4073ecae6e 100644 --- a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx +++ b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx @@ -326,43 +326,45 @@ export default class TaskRoleContainerList extends React.Component { getColumns(showDebugInfo) { const optionalColumns = [ { - key: 'nodeName', - name: 'Node Name', + key: 'startTime', + name: 'Start Time', headerClassName: FontClassNames.medium, - minWidth: 100, + minWidth: 150, + maxWidth: 200, isResizable: true, onRender: item => { return (
- {item.podNodeName} + {printDateTime(DateTime.fromISO(item.startTime))}
); }, }, { - key: 'exitCode', - name: 'Exit Code', + key: 'completionTime', + name: 'Completion Time', headerClassName: FontClassNames.medium, - minWidth: 100, + minWidth: 150, + maxWidth: 200, isResizable: true, onRender: item => { return (
- {item.containerExitCode} + {printDateTime(DateTime.fromISO(item.completionTime))}
); }, }, { - key: 'exitType', - name: 'Exit Type', + key: 'nodeName', + name: 'Node Name', headerClassName: FontClassNames.medium, - minWidth: 150, + minWidth: 100, isResizable: true, onRender: item => { return (
- {item.containerExitSpec.type} + {item.podNodeName}
); }, @@ -450,7 +452,7 @@ export default class TaskRoleContainerList extends React.Component { name: 'No.', headerClassName: FontClassNames.medium, minWidth: 30, - maxWidth: 30, + maxWidth: 50, isResizable: true, onRender: (item, idx) => { return ( @@ -534,7 +536,7 @@ export default class TaskRoleContainerList extends React.Component { className: FontClassNames.mediumPlus, headerClassName: FontClassNames.medium, minWidth: 35, - maxWidth: 35, + maxWidth: 50, isResizable: true, onRender: item => { const gpuAttr = isNil(item.containerGpus) @@ -590,57 +592,62 @@ export default class TaskRoleContainerList extends React.Component { name: 'Status', headerClassName: FontClassNames.medium, minWidth: 100, + maxWidth: 150, isResizable: true, onRender: item => , }, { - key: 'startTime', - name: 'Start Time', + key: 'retryCount', + name: 'Retries', headerClassName: FontClassNames.medium, - minWidth: 150, + minWidth: 50, + maxWidth: 100, isResizable: true, - onRender: item => { + onRender: (item, idx) => { return ( -
- {printDateTime(DateTime.fromISO(item.startTime))} +
+ {item.totalRetriedCount}
); }, }, { - key: 'completionTime', - name: 'Completion Time', + key: 'exitCode', + name: 'Exit Code', headerClassName: FontClassNames.medium, - minWidth: 150, + minWidth: 100, + maxWidth: 150, isResizable: true, onRender: item => { return (
- {printDateTime(DateTime.fromISO(item.completionTime))} + {item.containerExitCode}
); }, }, { - key: 'retryCount', - name: 'Retries', + key: 'exitType', + name: 'Exit Type', headerClassName: FontClassNames.medium, - minWidth: 50, + minWidth: 150, + maxWidth: 200, isResizable: true, - onRender: (item, idx) => { + onRender: item => { return ( -
- {item.totalRetriedCount} +
+ {item.containerExitSpec.type}
); }, }, { key: 'info', - name: 'Info', + name: 'Info & Logs', className: localCss.pa0I, headerClassName: FontClassNames.medium, minWidth: 330, + maxWidth: 500, onRender: item => (
Date: Mon, 6 Jul 2020 18:32:39 +0800 Subject: [PATCH 4/6] fix --- .../components/task-role-container-list.jsx | 51 +++++++++++++++++-- .../job-detail/components/task-role.jsx | 4 +- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx index 4073ecae6e..a577a399e6 100644 --- a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx +++ b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx @@ -325,6 +325,21 @@ export default class TaskRoleContainerList extends React.Component { getColumns(showDebugInfo) { const optionalColumns = [ + { + key: 'accountableRetries', + name: 'Accountable Retries', + headerClassName: FontClassNames.medium, + minWidth: 150, + maxWidth: 200, + isResizable: true, + onRender: (item, idx) => { + return ( +
+ {item.totalRetriedCount} +
+ ); + }, + }, { key: 'startTime', name: 'Start Time', @@ -335,7 +350,7 @@ export default class TaskRoleContainerList extends React.Component { onRender: item => { return (
- {printDateTime(DateTime.fromISO(item.startTime))} + {printDateTime(DateTime.fromMillis(item.startTime))}
); }, @@ -350,7 +365,37 @@ export default class TaskRoleContainerList extends React.Component { onRender: item => { return (
- {printDateTime(DateTime.fromISO(item.completionTime))} + {printDateTime(DateTime.fromMillis(item.completionTime))} +
+ ); + }, + }, + { + key: 'currentAttemptLaunchedTime', + name: 'Current Attempt Launched Time', + headerClassName: FontClassNames.medium, + minWidth: 150, + maxWidth: 200, + isResizable: true, + onRender: item => { + return ( +
+ {printDateTime(DateTime.fromMillis(item.startTime))} +
+ ); + }, + }, + { + key: 'currentAttemptCompletedTime', + name: 'Current Attempt Completion Time', + headerClassName: FontClassNames.medium, + minWidth: 150, + maxWidth: 200, + isResizable: true, + onRender: item => { + return ( +
+ {printDateTime(DateTime.fromMillis(item.completionTime))}
); }, @@ -597,7 +642,7 @@ export default class TaskRoleContainerList extends React.Component { onRender: item => , }, { - key: 'retryCount', + key: 'retries', name: 'Retries', headerClassName: FontClassNames.medium, minWidth: 50, diff --git a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role.jsx b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role.jsx index dd0557cc27..a2374eb237 100644 --- a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role.jsx +++ b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role.jsx @@ -179,8 +179,8 @@ export default class TaskRole extends React.Component { {/* right */} { this.setState({ showDebugInfo: checked, From 0f0b9041aa9afcf14544438e93708eea4e8d7dbe Mon Sep 17 00:00:00 2001 From: debuggy Date: Mon, 6 Jul 2020 19:13:37 +0800 Subject: [PATCH 5/6] update --- .../components/task-role-container-list.jsx | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx index a577a399e6..057a5340de 100644 --- a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx +++ b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx @@ -335,7 +335,7 @@ export default class TaskRoleContainerList extends React.Component { onRender: (item, idx) => { return (
- {item.totalRetriedCount} + {item.accountableRetries}
); }, @@ -350,7 +350,7 @@ export default class TaskRoleContainerList extends React.Component { onRender: item => { return (
- {printDateTime(DateTime.fromMillis(item.startTime))} + {printDateTime(DateTime.fromMillis(item.createdTime))}
); }, @@ -365,7 +365,7 @@ export default class TaskRoleContainerList extends React.Component { onRender: item => { return (
- {printDateTime(DateTime.fromMillis(item.completionTime))} + {printDateTime(DateTime.fromMillis(item.completedTime))}
); }, @@ -374,13 +374,15 @@ export default class TaskRoleContainerList extends React.Component { key: 'currentAttemptLaunchedTime', name: 'Current Attempt Launched Time', headerClassName: FontClassNames.medium, - minWidth: 150, - maxWidth: 200, + minWidth: 200, + maxWidth: 250, isResizable: true, onRender: item => { return (
- {printDateTime(DateTime.fromMillis(item.startTime))} + {printDateTime( + DateTime.fromMillis(item.currentAttemptLaunchedTime), + )}
); }, @@ -389,13 +391,15 @@ export default class TaskRoleContainerList extends React.Component { key: 'currentAttemptCompletedTime', name: 'Current Attempt Completion Time', headerClassName: FontClassNames.medium, - minWidth: 150, - maxWidth: 200, + minWidth: 250, + maxWidth: 250, isResizable: true, onRender: item => { return (
- {printDateTime(DateTime.fromMillis(item.completionTime))} + {printDateTime( + DateTime.fromMillis(item.currentAttemptCompletedTime), + )}
); }, @@ -409,7 +413,7 @@ export default class TaskRoleContainerList extends React.Component { onRender: item => { return (
- {item.podNodeName} + {item.containerNodeName}
); }, @@ -512,7 +516,7 @@ export default class TaskRoleContainerList extends React.Component { name: 'IP', className: FontClassNames.mediumPlus, headerClassName: FontClassNames.medium, - minWidth: 80, + minWidth: 90, maxWidth: 140, isResizable: true, fieldName: 'containerIp', @@ -542,8 +546,8 @@ export default class TaskRoleContainerList extends React.Component { name: 'Ports', className: FontClassNames.mediumPlus, headerClassName: FontClassNames.medium, - minWidth: 120, - maxWidth: 200, + minWidth: 150, + maxWidth: 300, isResizable: true, onRender: item => { const ports = item.containerPorts; @@ -581,7 +585,7 @@ export default class TaskRoleContainerList extends React.Component { className: FontClassNames.mediumPlus, headerClassName: FontClassNames.medium, minWidth: 35, - maxWidth: 50, + maxWidth: 60, isResizable: true, onRender: item => { const gpuAttr = isNil(item.containerGpus) @@ -650,9 +654,7 @@ export default class TaskRoleContainerList extends React.Component { isResizable: true, onRender: (item, idx) => { return ( -
- {item.totalRetriedCount} -
+
{item.retries}
); }, }, @@ -691,7 +693,7 @@ export default class TaskRoleContainerList extends React.Component { name: 'Info & Logs', className: localCss.pa0I, headerClassName: FontClassNames.medium, - minWidth: 330, + minWidth: 300, maxWidth: 500, onRender: item => (
Date: Tue, 7 Jul 2020 11:00:02 +0800 Subject: [PATCH 6/6] fix --- .../components/task-role-container-list.jsx | 30 +++++++++---------- .../job-detail/components/task-role.jsx | 4 +-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx index 057a5340de..47d26ecb24 100644 --- a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx +++ b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role-container-list.jsx @@ -355,21 +355,6 @@ export default class TaskRoleContainerList extends React.Component { ); }, }, - { - key: 'completionTime', - name: 'Completion Time', - headerClassName: FontClassNames.medium, - minWidth: 150, - maxWidth: 200, - isResizable: true, - onRender: item => { - return ( -
- {printDateTime(DateTime.fromMillis(item.completedTime))} -
- ); - }, - }, { key: 'currentAttemptLaunchedTime', name: 'Current Attempt Launched Time', @@ -404,6 +389,21 @@ export default class TaskRoleContainerList extends React.Component { ); }, }, + { + key: 'completionTime', + name: 'Completion Time', + headerClassName: FontClassNames.medium, + minWidth: 150, + maxWidth: 200, + isResizable: true, + onRender: item => { + return ( +
+ {printDateTime(DateTime.fromMillis(item.completedTime))} +
+ ); + }, + }, { key: 'nodeName', name: 'Node Name', diff --git a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role.jsx b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role.jsx index a2374eb237..90d13d0682 100644 --- a/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role.jsx +++ b/src/webportal/src/app/job/job-view/fabric/job-detail/components/task-role.jsx @@ -179,8 +179,8 @@ export default class TaskRole extends React.Component { {/* right */} { this.setState({ showDebugInfo: checked,