Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { FormTextField } from './form-text-field';
import { FormPage } from './form-page';
import { FormSpinButton } from './form-spin-button';
import { VirtualCluster } from './virtual-cluster';
import { JobType } from './job-type';
import Card from '../../components/card';
import { JobBasicInfo } from '../models/job-basic-info';
import { PROTOCOL_TOOLTIPS } from '../utils/constants';
Expand All @@ -37,7 +38,7 @@ const JOB_NAME_REGX = /^[A-Za-z0-9\-._~]+$/;

export const JobInformation = React.memo(
({ jobInformation, onChange, advanceFlag }) => {
const { name, virtualCluster, jobRetryCount } = jobInformation;
const { name, virtualCluster, jobRetryCount, jobType } = jobInformation;

const onChangeProp = useCallback(
(type, value) => {
Expand All @@ -59,6 +60,11 @@ export const JobInformation = React.memo(
[onChangeProp],
);

const onJobTypeChange = useCallback(
jobType => onChangeProp('jobType', jobType),
[onChangeProp],
);

const onRetryCountChange = useCallback(
val => onChangeProp('jobRetryCount', val),
[onChangeProp],
Expand Down Expand Up @@ -89,6 +95,10 @@ export const JobInformation = React.memo(
onChange={onRetryCountChange}
/>
)}
<JobType
onChange={onJobTypeChange}
jobType={jobType}
/>
</FormPage>
</Card>
);
Expand Down
64 changes: 64 additions & 0 deletions src/webportal/src/app/job-submission/components/job-type.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React, { useMemo, useCallback } from 'react';
import { BasicSection } from './basic-section';
import { Dropdown } from 'office-ui-fabric-react';
import { FormShortSection } from './form-page';
import PropTypes from 'prop-types';
import context from './context';

export const JobType = React.memo(props => {
const { onChange, jobType } = props;
const jobTypes = ['others', 'training', 'inference'];

const options = useMemo(
() =>
jobTypes.map((jobType, index) => {
return {
key: `jobType_${index}`,
text: jobType,
};
}),
[jobTypes],
);

const _onChange = useCallback(
(_, item) => {
if (onChange !== undefined) {
onChange(item.text);
if (item.text === 'inference') {
alert(
`Inference jobs have three forced parameters:
1. INTERNAL_SERVER_IP=$PAI_HOST_IP_taskrole_0 : Fix value, used to inference service IP
2. INTERNAL_SERVER_PORT=$PAI_PORT_LIST_taskrole_0_http : Fixed Value used to inference service port
3. API_KEY="...": A random generated string, can be set arbitrarily)
The three parameters will be automatically added to your job parameters upon switching to inference job type.
`,
);
}
}
},
[onChange],
);

const jobTypeIndex = options.findIndex(value => value.text === jobType);
return (
<BasicSection sectionLabel={'Job type'}>
<FormShortSection>
<Dropdown
placeholder='Select an option'
options={options}
onChange={_onChange}
selectedKey={jobTypeIndex === -1 ? null : `jobType_${jobTypeIndex}`}
/>
</FormShortSection>
</BasicSection>
);
});

JobType.propTypes = {
onChange: PropTypes.func,
jobType: PropTypes.string,
};
31 changes: 29 additions & 2 deletions src/webportal/src/app/job-submission/job-submission-page.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React, { useState, useCallback, useEffect, useMemo } from 'react';
import React, { useState, useCallback, useEffect, useMemo, use } from 'react';
import { Fabric, Stack, StackItem, Dropdown } from 'office-ui-fabric-react';
import { isNil, isEmpty, get, cloneDeep } from 'lodash';
import PropTypes from 'prop-types';
Expand Down Expand Up @@ -250,7 +250,7 @@ export const JobSubmissionPage = ({
break;
}
}
} catch {} // ignore all exceptions here
} catch { } // ignore all exceptions here
if (!isEmpty(defaultStorageConfig)) {
const storagePlugin = {
plugin: STORAGE_PLUGIN,
Expand Down Expand Up @@ -386,6 +386,33 @@ export const JobSubmissionPage = ({
.catch(alert);
}, [jobInformation.virtualCluster]);

useEffect(() => {
if (jobInformation.jobType === 'inference') {
const hasApiKey = parameters.find(param => param.key === 'API_KEY');
const hasInternalServerIp = parameters.find(param => param.key === 'INTERNAL_SERVER_IP');
const hasInternalServerPort = parameters.find(param => param.key === 'INTERNAL_SERVER_PORT');
if (!hasApiKey || !hasInternalServerIp || !hasInternalServerPort) {
const newParameters = [...parameters];
if (!hasInternalServerIp) {
// set fixed INTERNAL_SERVER_IP
newParameters.push({ key: 'INTERNAL_SERVER_IP', value: '$PAI_HOST_IP_taskrole_0' });
}
if (!hasInternalServerPort) {
// set fixed INTERNAL_SERVER_PORT
newParameters.push({ key: 'INTERNAL_SERVER_PORT', value: '$PAI_PORT_LIST_taskrole_0_http' });
}
if (!hasApiKey) {
{
// set a random generated api key
const randomKey = crypto.randomUUID();
newParameters.push({ key: 'API_KEY', value: randomKey });
}
}
setParameters(newParameters);
}
}
}, [jobInformation.jobType, parameters]);

const onTemplateChange = useCallback((_, item) => {
if (item.key === 'No') {
return;
Expand Down
7 changes: 5 additions & 2 deletions src/webportal/src/app/job-submission/models/job-basic-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,21 @@ import { isEmpty, get } from 'lodash';

export class JobBasicInfo {
constructor(props) {
const { name, jobRetryCount, virtualCluster } = props;
const { name, jobRetryCount, virtualCluster, jobType} = props;
this.name = name || '';
this.jobRetryCount = jobRetryCount || 0;
this.virtualCluster = virtualCluster || '';
this.jobType = jobType || '';
}

static fromProtocol(protocol) {
const { name, jobRetryCount } = protocol;
const { name, jobRetryCount, jobType } = protocol;
const virtualCluster = get(protocol, 'defaults.virtualCluster', 'default');
return new JobBasicInfo({
name: name,
jobRetryCount: jobRetryCount,
virtualCluster: virtualCluster,
jobType: jobType,
});
}

Expand All @@ -59,6 +61,7 @@ export class JobBasicInfo {
name: this.name,
type: 'job',
jobRetryCount: this.jobRetryCount,
jobType: this.jobType,
};
}
}
2 changes: 2 additions & 0 deletions src/webportal/src/app/job-submission/models/job-protocol.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class JobProtocol {
const {
name,
jobRetryCount,
jobType,
prerequisites,
parameters,
taskRoles,
Expand All @@ -53,6 +54,7 @@ export class JobProtocol {
this.contributor = contributor || '';
this.type = 'job';
this.jobRetryCount = jobRetryCount || 0;
this.jobType = jobType || 'others';
this.prerequisites = prerequisites || [];
this.parameters = parameters || {};
this.taskRoles = taskRoles || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ export const jobProtocolSchema = Joi.object().keys({
version: [Joi.string(), Joi.number()],
contributor: Joi.string(),
description: Joi.string(),
jobType: Joi.string().valid(['others', 'training', 'inference']).default('others'),

prerequisites: Joi.array()
.items(prerequisitesSchema)
Expand Down
Loading