Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
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
24 changes: 19 additions & 5 deletions .github/workflows/build-deploy-changes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,27 @@ jobs:
--overwrite-existing
kubelogin convert-kubeconfig -l azurecli
kubectl config use-context ${{ secrets.KUBERNETES_CLUSTER }}
# Replace "webportal" with "webportal-dind" if "webportal" is changed
services_to_deploy="${{ steps.changes.outputs.folders }}"
if echo " $services_to_deploy " | grep -q " webportal "; then
tmp=""
for s in $services_to_deploy; do
[ "$s" = "webportal" ] && continue
[ "$s" = "webportal-dind" ] && continue
tmp="$tmp $s"
done
services_to_deploy="$tmp webportal-dind"
services_to_deploy=$(echo "$services_to_deploy" | xargs)
fi
echo "Final services to deploy: $services_to_deploy"

echo "${{ secrets.PAI_CLUSTER_NAME }}" > cluster_id
echo "Stopping changed pai services \"${{ steps.changes.outputs.folders }}\" on ${{ secrets.PAI_CLUSTER_NAME }} ..."
$GITHUB_WORKSPACE/paictl.py service stop -n ${{ steps.changes.outputs.folders }} < cluster_id
echo "Stopping changed pai services $services_to_deploy on ${{ secrets.PAI_CLUSTER_NAME }} ..."
$GITHUB_WORKSPACE/paictl.py service stop -n $services_to_deploy < cluster_id
echo "Pushing config to cluster \"${{ secrets.PAI_CLUSTER_NAME }}\" ..."
$GITHUB_WORKSPACE/paictl.py config push -m service -p $GITHUB_WORKSPACE/config/cluster-configuration < cluster_id
echo "Starting to update \"${{ steps.changes.outputs.folders }}\" on ${{ secrets.PAI_CLUSTER_NAME }} ..."
$GITHUB_WORKSPACE/paictl.py service start -n ${{ steps.changes.outputs.folders }} < cluster_id
$GITHUB_WORKSPACE/paictl.py config push -m service -p $GITHUB_WORKSPACE/config/cluster-configuration < cluster_id
echo "Starting to update $services_to_deploy on ${{ secrets.PAI_CLUSTER_NAME }} ..."
$GITHUB_WORKSPACE/paictl.py service start -n $services_to_deploy < cluster_id
kubectl get pod
kubectl get service

Expand Down
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
62 changes: 62 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,62 @@
// 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';

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,
};
}),
);

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 : Fixed 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 ? "jobType_0" : `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 { useState, useCallback, useEffect, useMemo } 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]);

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