Skip to content

Commit

Permalink
feat(mis): 管理系统未结束作业新增结束操作 (#968)
Browse files Browse the repository at this point in the history
与门户系统类似,新增结束作业操作

![image](https://github.com/PKUHPC/SCOW/assets/140392039/7ced3259-8d96-4cca-ad09-e47b2aa096fc)
与门户系统不同,增加了权限校验:
```typescript
const { job, jobAccessible } = await checkJobAccessible(jobId, cluster, info);

if (jobAccessible === "NotAllowed") {
  return { 403: null };
} else if (jobAccessible === "NotFound") {
  return { 404: { code: "JOB_NOT_FOUND" } as const };
}

```
  • Loading branch information
Miracle575 authored Nov 11, 2023
1 parent a79aa10 commit f6f84b6
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 2 deletions.
7 changes: 7 additions & 0 deletions .changeset/tame-crews-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@scow/mis-server": minor
"@scow/mis-web": minor
"@scow/grpc-api": minor
---

管理系统未结束作业新增结束操作
16 changes: 16 additions & 0 deletions apps/mis-server/src/services/job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,5 +375,21 @@ export const jobServiceServer = plugin((server) => {
}

},

cancelJob: async ({ request, logger }) => {
const { cluster, userId, jobId } = request;

await server.ext.clusters.callOnOne(
cluster,
logger,
async (client) => {
await asyncClientCall(client.job, "cancelJob", {
userId, jobId,
});
},
);

return [{}];
},
});
});
1 change: 1 addition & 0 deletions apps/mis-web/src/apis/api.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ export const mockApi: MockApi<typeof api> = {
getAllAccounts: async () => ({ totalCount: mockAccounts.length, results: mockAccounts }),
changeJobTimeLimit: async () => null,
queryJobTimeLimit: async () => ({ result: 10 }),
cancelJob: async () => null,
createAccount: async () => { return {}; },
dewhitelistAccount: async () => null,
whitelistAccount: async () => null,
Expand Down
2 changes: 2 additions & 0 deletions apps/mis-web/src/apis/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import type { SetAsInitAdminSchema } from "src/pages/api/init/setAsInitAdmin";
import type { UnsetInitAdminSchema } from "src/pages/api/init/unsetInitAdmin";
import type { UserExistsSchema } from "src/pages/api/init/userExists";
import type { AddBillingItemSchema } from "src/pages/api/job/addBillingItem";
import type { CancelJobSchema } from "src/pages/api/job/cancelJob";
import type { ChangeJobTimeLimitSchema } from "src/pages/api/job/changeJobTimeLimit";
import type { GetAvailableBillingTableSchema } from "src/pages/api/job/getAvailableBillingTable";
import type { GetBillingItemsSchema } from "src/pages/api/job/getBillingItems";
Expand Down Expand Up @@ -89,6 +90,7 @@ import type { UnsetAdminSchema } from "src/pages/api/users/unsetAdmin";


export const api = {
cancelJob: apiClient.fromTypeboxRoute<typeof CancelJobSchema>("DELETE", "/api/job/cancelJob"),
changeJobPrice: apiClient.fromTypeboxRoute<typeof ChangeJobPriceSchema>("PATCH", "/api/admin/changeJobPrice"),
changePasswordAsPlatformAdmin: apiClient.fromTypeboxRoute<typeof ChangePasswordAsPlatformAdminSchema>("PATCH", "/api/admin/changePassword"),
changeStorageQuota: apiClient.fromTypeboxRoute<typeof ChangeStorageQuotaSchema>("PUT", "/api/admin/changeStorage"),
Expand Down
3 changes: 3 additions & 0 deletions apps/mis-web/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,9 @@ export default {
limit: "Job Time Limit",
changeLimit: "Modify Job Time Limit",
gpus: "Number of GPU Cards",
finishJobButton: "Finish",
finishJobConfirm: "Are you sure you want to finish this task?",
finishJobSuccess: "Request to finish the task has been submitted!",
},
},
profile: {
Expand Down
3 changes: 3 additions & 0 deletions apps/mis-web/src/i18n/zh_cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,9 @@ export default {
limit: "作业时间限制",
changeLimit: "修改作业时限",
gpus: "GPU卡数",
finishJobButton: "结束",
finishJobConfirm: "确定结束这个任务吗?",
finishJobSuccess: "任务结束请求已经提交!",
},
},
profile:{
Expand Down
20 changes: 18 additions & 2 deletions apps/mis-web/src/pageComponents/job/RunningJobTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

import { useDidUpdateEffect } from "@scow/lib-web/build/utils/hooks";
import { getI18nConfigCurrentText } from "@scow/lib-web/build/utils/i18n";
import { Button, Form, Input, InputNumber, Select, Space, Table } from "antd";
import { Button, Form, Input, InputNumber, message, Popconfirm, Select, Space, Table } from "antd";
import React, { useCallback, useMemo, useRef, useState } from "react";
import { useAsync } from "react-async";
import { useStore } from "simstate";
Expand Down Expand Up @@ -298,11 +298,27 @@ export const RunningJobInfoTable: React.FC<JobInfoTableProps> = ({

<Table.Column<RunningJobInfo>
title={t(pCommon("more"))}
width="9%"
width="12%"
fixed="right"
render={(_, r) => (
<Space>
<a onClick={() => setPreviewItem(r)}>{t(pCommon("detail"))}</a>
<Popconfirm
title={t(p("finishJobConfirm"))}
onConfirm={async () =>
api.cancelJob({
query: {
cluster: r.cluster.id,
jobId: r.jobId,
},
}).then(() => {
message.success(t(p("finishJobSuccess")));
reload();
})
}
>
<a>{t(p("finishJobButton"))}</a>
</Popconfirm>
<ChangeJobTimeLimitModalLink
reload={reload}
data={[r]}
Expand Down
82 changes: 82 additions & 0 deletions apps/mis-web/src/pages/api/job/cancelJob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Copyright (c) 2022 Peking University and Peking University Institute for Computing and Digital Economy
* SCOW is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

import { typeboxRouteSchema } from "@ddadaal/next-typed-api-routes-runtime";
import { asyncUnaryCall } from "@ddadaal/tsgrpc-client";
import { status } from "@grpc/grpc-js";
import { JobServiceClient } from "@scow/protos/build/server/job";
import { Type } from "@sinclair/typebox";
import { authenticate } from "src/auth/server";
import { OperationResult, OperationType } from "src/models/operationLog";
import { checkJobAccessible } from "src/server/jobAccessible";
import { callLog } from "src/server/operationLog";
import { getClient } from "src/utils/client";
import { route } from "src/utils/route";
import { handlegRPCError, parseIp } from "src/utils/server";

export const CancelJobSchema = typeboxRouteSchema({
method: "DELETE",

query: Type.Object({
cluster: Type.String(),
jobId: Type.String(),
}),

responses: {
204: Type.Null(),
/** 用户不能结束这个作业 */
403: Type.Null(),
/** 作业未找到 */
404: Type.Object({ code: Type.Literal("JOB_NOT_FOUND") }),
},
});

const auth = authenticate(() => true);

export default /* #__PURE__*/route(CancelJobSchema, async (req, res) => {

const info = await auth(req, res);

if (!info) { return; }

const { cluster, jobId } = req.query;

const { job, jobAccessible } = await checkJobAccessible(jobId, cluster, info);

if (jobAccessible === "NotAllowed") {
return { 403: null };
} else if (jobAccessible === "NotFound") {
return { 404: { code: "JOB_NOT_FOUND" } as const };
}

const client = getClient(JobServiceClient);

const logInfo = {
operatorUserId: info.identityId,
operatorIp: parseIp(req) ?? "",
operationTypeName: OperationType.endJob,
operationTypePayload: {
jobId: +jobId, accountName: job.account,
},
};

return asyncUnaryCall(client, "cancelJob", {
jobId: +jobId, userId: info.identityId, cluster,
}).then(async () => {
await callLog(logInfo, OperationResult.SUCCESS);
return { 204: null };
}, handlegRPCError({
[status.NOT_FOUND]: () => ({ 404: { code: "JOB_NOT_FOUND" } } as const),
},
async () => await callLog(logInfo, OperationResult.FAIL),
));
});
10 changes: 10 additions & 0 deletions protos/server/job.proto
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ message QueryJobTimeLimitRequest {
string job_id = 2;
}

message CancelJobRequest {
string cluster = 1;
string user_id = 2;
uint32 job_id = 3;
}

message CancelJobResponse {}

message GetBillingItemsRequest {
// if not specified, return default price items
optional string tenant_name = 1;
Expand Down Expand Up @@ -152,6 +160,8 @@ service JobService {
rpc ChangeJobTimeLimit(ChangeJobTimeLimitRequest) returns (ChangeJobTimeLimitResponse);
rpc QueryJobTimeLimit(QueryJobTimeLimitRequest) returns (QueryJobTimeLimitResponse);

rpc CancelJob(CancelJobRequest) returns (CancelJobResponse);

rpc GetBillingItems(GetBillingItemsRequest) returns (GetBillingItemsResponse);

// ALREADY_EXISTS: item_id already exists
Expand Down

0 comments on commit f6f84b6

Please sign in to comment.