Родитель
0f25c1866e
Коммит
63d10b8e2c
|
@ -0,0 +1,5 @@
|
|||
node_modules
|
||||
*.log
|
||||
!.vscode/
|
||||
.vscode/extensions.json
|
||||
.vscode/settings.json
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"printWidth": 120,
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true
|
||||
}
|
350
README.md
350
README.md
|
@ -1,46 +1,324 @@
|
|||
# Motivation
|
||||
# OpenPAI JS SDK
|
||||
|
||||
This SDK is designed to facilitate the developers of [OpenPAI](https://github.com/microsoft/pai) by providing below functions
|
||||
The `JavaScript` SDK for `OpenPAI`.
|
||||
|
||||
- RESTful API Wrapping
|
||||
- Cluster Management in local environment
|
||||
- Unified Storage Interface
|
||||
- Front End Support
|
||||
- Job Config Processing
|
||||
## Installation
|
||||
|
||||
# Cluster Management in local environment
|
||||
|
||||
To let users easily access multiple clusters, the SDK records the necessary configuration of each cluster in a local file (e.g. `~/.openpai/clusters.yaml`). In the file, a list of clusters are stored, and each of them has a alias (`${cluster-alias}`) to be addressed.
|
||||
|
||||
To accelerate cluster loading, the SDK may also cache some not-frequently-changed cluster information (e.g. virtual clusters, storages). And the updating method is also provided to synchronize with cluster.
|
||||
|
||||
# Unified Storage Interface
|
||||
|
||||
Multiple types of storages are supported by OpenPAI, however, the end user and developers should not be bothered by too much details of it. The SDK provides an abstract storage accessing methods to let users access the storages.
|
||||
|
||||
For the cluster (client) object in SDK, it would provide path parsing and storage accessing methods (`list, getinfo, upload, download, delete`) with the following type of path
|
||||
```bash
|
||||
${configname}~${mount-index}/path/to/destination
|
||||
```
|
||||
|
||||
The `${configname}` and `${mount-index}` could be found in the the retrieved [storage config](https://github.com/microsoft/pai/tree/master/contrib/storage_plugin#config-data-structure-) by the [get storage config API](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/microsoft/pai/master/src/rest-server/docs/swagger.yaml#operation/getStorageConfigs), which contains a list of storage paths like
|
||||
```json
|
||||
{
|
||||
"name": "configname",
|
||||
"mountInfos": [
|
||||
{
|
||||
"server": "servername",
|
||||
"path": "server/sub/path"
|
||||
},
|
||||
]
|
||||
}
|
||||
npm install --save microsoft/pai#openpai-js-sdk
|
||||
```
|
||||
|
||||
For end user, the SDK / Front End could be able to translate the path like
|
||||
```bash
|
||||
pai://${cluster-alias}/${configname}~${mount-index}/path/to/destination
|
||||
## RESTful APIs
|
||||
|
||||
Initialize the `openPAIClient`
|
||||
|
||||
```ts
|
||||
const cluster: IPAICluster = {
|
||||
username: '<username>',
|
||||
password: '<password>',
|
||||
token: '<token>',
|
||||
rest_server_uri: '<The host>/rest-server'
|
||||
};
|
||||
const openPAIClient = new OpenPAIClient(cluster);
|
||||
```
|
||||
to the real remote path in the storage configs provisioned by the cluster. Here, `${cluster-alias}` is the cluster alias that could be indexed in local environment.
|
||||
|
||||
### Job related
|
||||
|
||||
- [x] List jobs (GET /api/v1/jobs)
|
||||
|
||||
```ts
|
||||
list = await openPAIClient.job.list();
|
||||
list = await openPAIClient.job.list('username=xxx');
|
||||
```
|
||||
|
||||
- [x] Get job (GET /api/v2/user/{username}/jobs/{jobname})
|
||||
|
||||
```ts
|
||||
job = await openPAIClient.job.get(username, jobname);
|
||||
```
|
||||
|
||||
- [x] Get framework info (GET /api/v2/jobs/{username}~{jobname})
|
||||
|
||||
```ts
|
||||
info = await openPAIClient.job.getFrameworkInfo(username, jobname);
|
||||
```
|
||||
|
||||
- [x] Get job config (GET /api/v2/jobs/{username}~{jobname}/config)
|
||||
|
||||
```ts
|
||||
config = await openPAIClient.job.getConfig(username, jobname);
|
||||
```
|
||||
|
||||
- [x] Get job ssh info (GET /api/v1/user/{username}/jobs/{jobname}/ssh)
|
||||
|
||||
```ts
|
||||
sshInfo = await openPAIClient.job.getSshInfo(username, jobname);
|
||||
```
|
||||
|
||||
- [x] Submit v1 job (POST /api/v1/user/{username}/jobs)
|
||||
|
||||
```ts
|
||||
await openPAIClient.job.submitV1((userName, config)
|
||||
```
|
||||
|
||||
- [x] Submit v2 job (POST /api/v2/jobs)
|
||||
|
||||
```ts
|
||||
await openPAIClient.job.submit(config);
|
||||
```
|
||||
|
||||
- [x] Remove job (DELETE /api/v2/user/{username}/jobs/{jobname})
|
||||
|
||||
```ts
|
||||
await openPAIClient.job.delete(username, jobname);
|
||||
```
|
||||
|
||||
- [x] Start/Stop job (PUT /api/v2/user/{username}/jobs/{jobname}/executionType)
|
||||
|
||||
```ts
|
||||
await openPAIClient.job.execute(username, jobname, 'START');
|
||||
await openPAIClient.job.execute(username, jobname, 'STOP');
|
||||
```
|
||||
|
||||
### User related
|
||||
|
||||
- [x] Get user (GET /api/v2/user/{username})
|
||||
|
||||
```ts
|
||||
user = await openPAIClient.user.get(username);
|
||||
```
|
||||
|
||||
- [x] List users (GET /api/v2/user/)
|
||||
|
||||
```ts
|
||||
list = await openPAIClient.user.list();
|
||||
```
|
||||
|
||||
- [x] Create user (POST /api/v2/user/)
|
||||
|
||||
```ts
|
||||
await openPAIClient.user.create(username, password, admin, email, virtualClusters);
|
||||
```
|
||||
|
||||
- [x] Delete user (DELETE /api/v2/user/{username})
|
||||
|
||||
```ts
|
||||
await openPAIClient.user.delete(username);
|
||||
```
|
||||
|
||||
- [x] Update user extension (PUT /api/v2/user/{username}/extension)
|
||||
|
||||
```ts
|
||||
await openPAIClient.user.updateExtension(username, {
|
||||
"extension-key1": "extension-value1",
|
||||
"extension-key2": "extension-value2",
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
- [x] Update user virtual cluster (PUT /api/v2/user/{username}/virtualcluster)
|
||||
|
||||
```ts
|
||||
await openPAIClient.user.updateVirtualcluster(username, ['vc1', 'vc2', ...]);
|
||||
```
|
||||
|
||||
- [x] Update user password (PUT /api/v2/user/{username}/password)
|
||||
|
||||
```ts
|
||||
await openPAIClient.user.updatePassword(username, oldPassword, newPassword);
|
||||
```
|
||||
|
||||
- [x] Update user email (PUT /api/v2/user/{username}/email)
|
||||
|
||||
```ts
|
||||
await openPAIClient.user.updateEmail(username, newEmail);
|
||||
```
|
||||
|
||||
- [x] Update user admin permission (PUT /api/v2/user/{username}/admin)
|
||||
|
||||
```ts
|
||||
await openPAIClient.user.updateAdminPermission(username, newAdminPermission);
|
||||
```
|
||||
|
||||
- [x] Update user group list (PUT /api/v2/user/{username}/grouplist)
|
||||
|
||||
```ts
|
||||
await openPAIClient.user.updateGroupList(username, ['group1', 'group2', ...]);
|
||||
```
|
||||
|
||||
- [x] Add group into user group list (PUT /api/v2/user/{username}/group)
|
||||
|
||||
```ts
|
||||
await openPAIClient.user.addGroup(username, groupName);
|
||||
```
|
||||
|
||||
- [x] Remove group from user group list (DELETE /api/v2/user/{username}/group)
|
||||
|
||||
```ts
|
||||
await openPAIClient.user.removeGroup(username, groupName);
|
||||
```
|
||||
|
||||
### VC related
|
||||
|
||||
- [x] List all virtual clusters (GET /api/v2/virtual-clusters)
|
||||
|
||||
```ts
|
||||
list = await openPAIClient.virtualCluster.list();
|
||||
```
|
||||
|
||||
- [x] Get node resource (GET /api/v2/virtual-clusters/nodeResource)
|
||||
|
||||
```ts
|
||||
resource = await openPAIClient.virtualCluster.getNodeResource();
|
||||
```
|
||||
|
||||
- [x] Get virtual cluster (GET /api/v2/virtual-clusters/{vcName})
|
||||
|
||||
```ts
|
||||
vc = await openPAIClient.virtualCluster.get(vcName);
|
||||
```
|
||||
|
||||
- [x] Create or update virtual cluster (PUT /api/v1/virtual-clusters/{vcName})
|
||||
|
||||
```ts
|
||||
await openPAIClient.virtualCluster.createOrUpdate(vcName, vcCapacity, vcMaxCapacity);
|
||||
```
|
||||
|
||||
- [x] Remove virtual cluster (DELETE /api/v1/virtual-clusters/{vcName})
|
||||
|
||||
```ts
|
||||
await openPAIClient.virtualCluster.delete(vcName);
|
||||
```
|
||||
|
||||
- [x] Change virtual cluster status (PUT /api/v1/virtual-clusters/{vcName}/status)
|
||||
|
||||
```ts
|
||||
await openPAIClient.virtualCluster.changeStatus(vcName, newStatus);
|
||||
```
|
||||
|
||||
- [ ] Get virtual cluster available resourceUnit (GET /api/v2/virtual-clusters/{vcName}/resourceUnits)
|
||||
|
||||
```json
|
||||
{
|
||||
"code":"NotImplementedError",
|
||||
"message":"getResourceUnits not implemented in yarn"
|
||||
}
|
||||
```
|
||||
|
||||
### Auth related
|
||||
|
||||
- [x] Get token (POST /api/v1/token)
|
||||
|
||||
```ts
|
||||
token = await openPAIClient.token();
|
||||
```
|
||||
|
||||
- [x] Get auth info (GET /api/v1/authn/info)
|
||||
|
||||
```ts
|
||||
info = await openPAIClient.authn.info();
|
||||
```
|
||||
|
||||
- [x] Basic login (POST /api/v1/authn/basic/login)
|
||||
|
||||
```ts
|
||||
loginInfo = await openPAIClient.authn.login();
|
||||
```
|
||||
|
||||
- [x] OIDC login (GET /api/v1/authn/oidc/login)
|
||||
|
||||
```ts
|
||||
redirect = await openPAIClient.authn.oidcLogin();
|
||||
```
|
||||
|
||||
- [x] OIDC logout (GET /api/v1/authn/oidc/logout)
|
||||
|
||||
```ts
|
||||
redirect = await openPAIClient.authn.oidcLogout();
|
||||
```
|
||||
|
||||
- [x] Get list of available tokens (portal token + application token) (GET /api/v1/token)
|
||||
|
||||
```ts
|
||||
tokens = await openPAIClient.auth.getTokens();
|
||||
```
|
||||
|
||||
- [x] Create an application access token (POST /api/v1/token/application)
|
||||
|
||||
```ts
|
||||
token = await openPAIClient.auth.createApplicationToken();
|
||||
```
|
||||
|
||||
- [x] Revoke a token (DELETE /api/v1/token/{token})
|
||||
|
||||
```ts
|
||||
await openPAIClient.auth.deleteToken(token);
|
||||
```
|
||||
|
||||
- [ ] OIDC return (GET/POST /api/v1/authn/oidc/return)
|
||||
|
||||
```text
|
||||
Web-browser will call this API automatically after OIDC login step.
|
||||
```
|
||||
|
||||
### Group related
|
||||
|
||||
- [ ] Create a group (POST /api/v2/group)
|
||||
- [ ] Change a group's extension
|
||||
(POST /api/v2/group/:groupname/extension)
|
||||
- [ ] Change a specific attribute in a nested group extension
|
||||
(PUT /api/v2/group/:groupname/extension/path/to/attr)
|
||||
- [ ] Change a group's description
|
||||
(POST /api/v2/group/:groupname/description)
|
||||
- [ ] Change a group's externalname, and bind it with another external group
|
||||
(POST /api/v2/group/:groupname/externalname)
|
||||
- [ ] Delete a group from system (DELETE /api/v2/group/:groupname)
|
||||
|
||||
### Storage
|
||||
|
||||
- [x] Get storage server data in the system (GET /api/v2/storage/server/{storage})
|
||||
|
||||
```ts
|
||||
await openPAIClient.storage.getServerByName(storage);
|
||||
```
|
||||
|
||||
- [ ] Remove storage server in the system (DELETE /api/v2/storage/server/{storage})
|
||||
- [x] Get storage server data in the system (GET /api/v2/storage/server)
|
||||
|
||||
```ts
|
||||
await openPAIClient.storage.getServer();
|
||||
await openPAIClient.storage.getServer(names);
|
||||
```
|
||||
|
||||
- [ ] Create storage server in the system (POST /api/v2/storage/server)
|
||||
- [ ] Update storage server in the system (PUT /api/v2/storage/server)
|
||||
- [x] Get storage config data in the system (GET /api/v2/storage/config/{storage})
|
||||
|
||||
```ts
|
||||
await openPAIClient.storage.getConfigByName(storage);
|
||||
```
|
||||
|
||||
- [ ] Remove storage config in the system (DELETE /api/v2/storage/config/{storage})
|
||||
- [x] Get storage config data in the system (GET /api/v2/storage/config)
|
||||
|
||||
```ts
|
||||
await openPAIClient.storage.getConfig();
|
||||
await openPAIClient.storage.getConfig(names);
|
||||
```
|
||||
|
||||
- [ ] Create storage config in system (POST /api/v2/storage/config)
|
||||
- [ ] Update storage config in system (PUT /api/v2/storage/config)
|
||||
|
||||
### Job history
|
||||
|
||||
- [ ] Check if job attempts is healthy (GET /api/v2/jobs/{user}~{job}/job-attempts/healthz)
|
||||
- [ ] Get all attempts of a job (GET /api/v2/jobs/{user}~{job}/job-attempts)
|
||||
- [ ] Get a specific attempt by attempt index
|
||||
(GET /api/v2/jobs/{user}~{job}/job-attempts/{attempt})
|
||||
|
||||
## Useful tools
|
||||
|
||||
- [ ] To be added...
|
||||
|
||||
# Contributing
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import { IAuthnInfo } from '../models/authn';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
/**
|
||||
* OpenPAI Authn client.
|
||||
*/
|
||||
export declare class AuthnClient extends OpenPAIBaseClient {
|
||||
private authnInfo?;
|
||||
constructor(cluster: IPAICluster);
|
||||
/**
|
||||
* Get authn information.
|
||||
*/
|
||||
info(): Promise<IAuthnInfo>;
|
||||
/**
|
||||
* OpenID Connect login.
|
||||
*/
|
||||
oidcLogin(queryString?: string): Promise<any>;
|
||||
/**
|
||||
* OpenID Connect logout.
|
||||
*/
|
||||
oidcLogout(queryString?: string): Promise<any>;
|
||||
/**
|
||||
* Get list of available tokens (portal token + application token).
|
||||
*/
|
||||
getTokens(token?: string): Promise<any>;
|
||||
/**
|
||||
* Create an application access token.
|
||||
*/
|
||||
createApplicationToken(token?: string): Promise<any>;
|
||||
/**
|
||||
* Revoke a token.
|
||||
*/
|
||||
deleteToken(deleteToken: string, accessToken?: string): Promise<any>;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const request = require("request-promise-native");
|
||||
const util_1 = require("../commom/util");
|
||||
const baseClient_1 = require("./baseClient");
|
||||
/**
|
||||
* OpenPAI Authn client.
|
||||
*/
|
||||
class AuthnClient extends baseClient_1.OpenPAIBaseClient {
|
||||
constructor(cluster) {
|
||||
super(cluster);
|
||||
}
|
||||
/**
|
||||
* Get authn information.
|
||||
*/
|
||||
async info() {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/info`);
|
||||
if (this.authnInfo === undefined) {
|
||||
this.authnInfo = JSON.parse(await request.get(url));
|
||||
}
|
||||
return this.authnInfo;
|
||||
}
|
||||
/**
|
||||
* OpenID Connect login.
|
||||
*/
|
||||
async oidcLogin(queryString) {
|
||||
const url = queryString ?
|
||||
util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/oidc/login?${queryString}`) :
|
||||
util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/oidc/login`);
|
||||
const res = await request.get(url);
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* OpenID Connect logout.
|
||||
*/
|
||||
async oidcLogout(queryString) {
|
||||
const url = queryString ?
|
||||
util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/oidc/logout?${queryString}`) :
|
||||
util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/oidc/logout`);
|
||||
const res = await request.get(url);
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* Get list of available tokens (portal token + application token).
|
||||
*/
|
||||
async getTokens(token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/token`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Create an application access token.
|
||||
*/
|
||||
async createApplicationToken(token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/token/application`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.post(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Revoke a token.
|
||||
*/
|
||||
async deleteToken(deleteToken, accessToken) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/token/${deleteToken}`);
|
||||
if (accessToken === undefined) {
|
||||
accessToken = await super.token();
|
||||
}
|
||||
const res = await request.delete(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
}
|
||||
exports.AuthnClient = AuthnClient;
|
|
@ -0,0 +1,23 @@
|
|||
import { ILoginInfo } from '../models/authn';
|
||||
import { IPAICluster, IPAIClusterInfo } from '../models/cluster';
|
||||
/**
|
||||
* OpenPAI basic client.
|
||||
*/
|
||||
export declare class OpenPAIBaseClient {
|
||||
protected static readonly TIMEOUT: number;
|
||||
protected cluster: IPAICluster;
|
||||
private cacheToken?;
|
||||
constructor(cluster: IPAICluster);
|
||||
/**
|
||||
* Get OpenPAI access token, will call /api/v1/token.
|
||||
*/
|
||||
token(): Promise<string>;
|
||||
/**
|
||||
* Basic login.
|
||||
*/
|
||||
login(): Promise<ILoginInfo>;
|
||||
/**
|
||||
* Get OpenPAI cluster info, will call /api/v1.
|
||||
*/
|
||||
getClusterInfo(): Promise<IPAIClusterInfo>;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const request = require("request-promise-native");
|
||||
const util_1 = require("../commom/util");
|
||||
/**
|
||||
* OpenPAI basic client.
|
||||
*/
|
||||
class OpenPAIBaseClient {
|
||||
constructor(cluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
/**
|
||||
* Get OpenPAI access token, will call /api/v1/token.
|
||||
*/
|
||||
async token() {
|
||||
if (this.cluster.token) {
|
||||
return this.cluster.token;
|
||||
}
|
||||
else if (!this.cacheToken || this.cacheToken.expireTime < Date.now()) {
|
||||
const res = await this.login();
|
||||
this.cacheToken = {
|
||||
expireTime: Date.now() + 3600 * 1000,
|
||||
token: res.token
|
||||
};
|
||||
}
|
||||
return this.cacheToken.token;
|
||||
}
|
||||
/**
|
||||
* Basic login.
|
||||
*/
|
||||
async login() {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/basic/login`);
|
||||
const res = await request.post(url, {
|
||||
form: {
|
||||
expiration: 4000,
|
||||
password: this.cluster.password,
|
||||
username: this.cluster.username
|
||||
},
|
||||
json: true,
|
||||
timeout: OpenPAIBaseClient.TIMEOUT
|
||||
});
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* Get OpenPAI cluster info, will call /api/v1.
|
||||
*/
|
||||
async getClusterInfo() {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
}
|
||||
OpenPAIBaseClient.TIMEOUT = 60 * 1000;
|
||||
exports.OpenPAIBaseClient = OpenPAIBaseClient;
|
|
@ -0,0 +1,68 @@
|
|||
import { IPAICluster } from '../models/cluster';
|
||||
import { IJobConfig, IJobConfigV1, IJobFrameworkInfo, IJobInfo, IJobSshInfo, IJobStatus } from '../models/job';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
/**
|
||||
* OpenPAI Job client.
|
||||
*/
|
||||
export declare class JobClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster);
|
||||
/**
|
||||
* List jobs, will call /api/v1/jobs.
|
||||
* @param query The query string.
|
||||
*/
|
||||
list(query?: string): Promise<IJobInfo[]>;
|
||||
/**
|
||||
* Get job status, will call /api/v2/user/{userName}/jobs/{jobName}.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
get(userName: string, jobName: string): Promise<IJobStatus>;
|
||||
/**
|
||||
* Delete a job, will call /api/v2/user/{userName}/jobs/{jobName}.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
delete(userName: string, jobName: string, token?: string): Promise<IJobStatus>;
|
||||
/**
|
||||
* Get job framework info, will call /api/v2/jobs/{userName}~{jobName}.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
getFrameworkInfo(userName: string, jobName: string): Promise<IJobFrameworkInfo>;
|
||||
/**
|
||||
* Get job config, will call /api/v2/jobs/{userName}~{jobName}/config.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
getConfig(userName: string, jobName: string): Promise<IJobConfig>;
|
||||
/**
|
||||
* Start or stop a job, will call /api/v1/user/{userName}/jobs/{jobName}/executionType.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
* @param type 'START' or 'STOP'.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
execute(userName: string, jobName: string, type: 'START' | 'STOP', token?: string): Promise<any>;
|
||||
/**
|
||||
* Submit a job, will call /api/v2/jobs.
|
||||
* @param jobConfig The job config.
|
||||
*/
|
||||
submit(jobConfig: IJobConfig, token?: string): Promise<void>;
|
||||
/**
|
||||
* Submit a v1 job, will call /api/v1/user/{username}/jobs.
|
||||
* @param jobConfig The job config.
|
||||
*/
|
||||
submitV1(userName: string, jobConfig: IJobConfigV1, token?: string): Promise<void>;
|
||||
/**
|
||||
* Get job SSH infomation, will call /api/v1/user/${userName}/jobs/${jobName}/ssh.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
getSshInfo(userName: string, jobName: string): Promise<IJobSshInfo>;
|
||||
/**
|
||||
* Get job SSH infomation, will call /api/v1/jobs/${jobName}/ssh.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
getSshInfo(jobName: string): Promise<IJobSshInfo>;
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const yaml = require("js-yaml");
|
||||
const request = require("request-promise-native");
|
||||
const util_1 = require("../commom/util");
|
||||
const baseClient_1 = require("./baseClient");
|
||||
/**
|
||||
* OpenPAI Job client.
|
||||
*/
|
||||
class JobClient extends baseClient_1.OpenPAIBaseClient {
|
||||
constructor(cluster) {
|
||||
super(cluster);
|
||||
}
|
||||
/**
|
||||
* List jobs, will call /api/v1/jobs.
|
||||
* @param query The query string.
|
||||
*/
|
||||
async list(query) {
|
||||
const url = query === undefined ?
|
||||
util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/jobs`) :
|
||||
util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/jobs?${query}`);
|
||||
return await request.get(url);
|
||||
}
|
||||
/**
|
||||
* Get job status, will call /api/v2/user/{userName}/jobs/{jobName}.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
async get(userName, jobName) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/jobs/${jobName}`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Delete a job, will call /api/v2/user/{userName}/jobs/{jobName}.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async delete(userName, jobName, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/jobs/${jobName}`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.delete(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
timeout: baseClient_1.OpenPAIBaseClient.TIMEOUT
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Get job framework info, will call /api/v2/jobs/{userName}~{jobName}.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
async getFrameworkInfo(userName, jobName) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Get job config, will call /api/v2/jobs/{userName}~{jobName}/config.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
async getConfig(userName, jobName) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}/config`);
|
||||
const res = await request.get(url);
|
||||
return yaml.safeLoad(res);
|
||||
}
|
||||
/**
|
||||
* Start or stop a job, will call /api/v1/user/{userName}/jobs/{jobName}/executionType.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
* @param type 'START' or 'STOP'.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async execute(userName, jobName, type, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/jobs/${jobName}/executionType`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.put(url, {
|
||||
body: JSON.stringify({
|
||||
value: type
|
||||
}),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
timeout: baseClient_1.OpenPAIBaseClient.TIMEOUT
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Submit a job, will call /api/v2/jobs.
|
||||
* @param jobConfig The job config.
|
||||
*/
|
||||
async submit(jobConfig, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/jobs`);
|
||||
const text = yaml.safeDump(jobConfig);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
await request.post(url, {
|
||||
body: text,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'text/yaml'
|
||||
},
|
||||
timeout: baseClient_1.OpenPAIBaseClient.TIMEOUT
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Submit a v1 job, will call /api/v1/user/{username}/jobs.
|
||||
* @param jobConfig The job config.
|
||||
*/
|
||||
async submitV1(userName, jobConfig, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/user/${userName}/jobs`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
return await request.post(url, {
|
||||
form: jobConfig,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
json: true,
|
||||
timeout: baseClient_1.OpenPAIBaseClient.TIMEOUT
|
||||
});
|
||||
}
|
||||
async getSshInfo(param1, param2) {
|
||||
const userName = param2 ? param1 : undefined;
|
||||
const jobName = param2 ? param2 : param1;
|
||||
const url = userName ?
|
||||
util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/user/${userName}/jobs/${jobName}/ssh`) :
|
||||
util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/jobs/${jobName}/ssh`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
}
|
||||
exports.JobClient = JobClient;
|
|
@ -0,0 +1,33 @@
|
|||
import { AuthnClient } from '..';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
import { JobClient } from './jobClient';
|
||||
import { StorageClient } from './storageClient';
|
||||
import { UserClient } from './userClient';
|
||||
import { VirtualClusterClient } from './virtualClusterClient';
|
||||
/**
|
||||
* OpenPAI Client.
|
||||
*/
|
||||
export declare class OpenPAIClient extends OpenPAIBaseClient {
|
||||
/**
|
||||
* OpenPAI Job Client.
|
||||
*/
|
||||
job: JobClient;
|
||||
/**
|
||||
* OpenPAI User Client.
|
||||
*/
|
||||
user: UserClient;
|
||||
/**
|
||||
* OpenPAI Virtual Cluster Client.
|
||||
*/
|
||||
virtualCluster: VirtualClusterClient;
|
||||
/**
|
||||
* OpenPAI Authn Client.
|
||||
*/
|
||||
authn: AuthnClient;
|
||||
/**
|
||||
* OpenPAI Storage Client.
|
||||
*/
|
||||
storage: StorageClient;
|
||||
constructor(cluster: IPAICluster);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const __1 = require("..");
|
||||
const baseClient_1 = require("./baseClient");
|
||||
const jobClient_1 = require("./jobClient");
|
||||
const storageClient_1 = require("./storageClient");
|
||||
const userClient_1 = require("./userClient");
|
||||
const virtualClusterClient_1 = require("./virtualClusterClient");
|
||||
/**
|
||||
* OpenPAI Client.
|
||||
*/
|
||||
class OpenPAIClient extends baseClient_1.OpenPAIBaseClient {
|
||||
constructor(cluster) {
|
||||
super(cluster);
|
||||
this.job = new jobClient_1.JobClient(cluster);
|
||||
this.user = new userClient_1.UserClient(cluster);
|
||||
this.virtualCluster = new virtualClusterClient_1.VirtualClusterClient(cluster);
|
||||
this.authn = new __1.AuthnClient(cluster);
|
||||
this.storage = new storageClient_1.StorageClient(cluster);
|
||||
}
|
||||
}
|
||||
exports.OpenPAIClient = OpenPAIClient;
|
|
@ -0,0 +1,29 @@
|
|||
import { IPAICluster } from '../models/cluster';
|
||||
import { IStorageConfig, IStorageServer } from '../models/storage';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
/**
|
||||
* OpenPAI Job client.
|
||||
*/
|
||||
export declare class StorageClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster);
|
||||
/**
|
||||
* Get storage informations.
|
||||
* @param names Filter storage server with names, default name empty will be ignored.
|
||||
*/
|
||||
getServer(names?: string, token?: string): Promise<IStorageServer[]>;
|
||||
/**
|
||||
* Get storage information.
|
||||
* @param storage The storage name.
|
||||
*/
|
||||
getServerByName(storage: string, token?: string): Promise<IStorageServer>;
|
||||
/**
|
||||
* Get storage config.
|
||||
* @param names Filter storage server with names, default name empty will be ignored.
|
||||
*/
|
||||
getConfig(names?: string, token?: string): Promise<IStorageConfig[]>;
|
||||
/**
|
||||
* Get storage config.
|
||||
* @param storage The storage name.
|
||||
*/
|
||||
getConfigByName(storage: string, token?: string): Promise<IStorageConfig>;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const util_1 = require("../commom/util");
|
||||
const baseClient_1 = require("./baseClient");
|
||||
const axios_1 = require("axios");
|
||||
/**
|
||||
* OpenPAI Job client.
|
||||
*/
|
||||
class StorageClient extends baseClient_1.OpenPAIBaseClient {
|
||||
constructor(cluster) {
|
||||
super(cluster);
|
||||
}
|
||||
/**
|
||||
* Get storage informations.
|
||||
* @param names Filter storage server with names, default name empty will be ignored.
|
||||
*/
|
||||
async getServer(names, token) {
|
||||
const query = names ? `?names=${names}` : '';
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/server${query}`, this.cluster.https);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await axios_1.default.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
/**
|
||||
* Get storage information.
|
||||
* @param storage The storage name.
|
||||
*/
|
||||
async getServerByName(storage, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/server/${storage}`, this.cluster.https);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await axios_1.default.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
/**
|
||||
* Get storage config.
|
||||
* @param names Filter storage server with names, default name empty will be ignored.
|
||||
*/
|
||||
async getConfig(names, token) {
|
||||
const query = names ? `?names=${names}` : '';
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/config${query}`, this.cluster.https);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await axios_1.default.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
/**
|
||||
* Get storage config.
|
||||
* @param storage The storage name.
|
||||
*/
|
||||
async getConfigByName(storage, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/config/${storage}`, this.cluster.https);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await axios_1.default.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
exports.StorageClient = StorageClient;
|
|
@ -0,0 +1,104 @@
|
|||
import { IPAICluster } from '../models/cluster';
|
||||
import { IUserInfo } from '../models/user';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
/**
|
||||
* OpenPAI User client.
|
||||
*/
|
||||
export declare class UserClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster);
|
||||
/**
|
||||
* Get user information.
|
||||
* @param userName The user name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
get(userName: string, token?: string): Promise<IUserInfo>;
|
||||
/**
|
||||
* Get all users.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
list(token?: string): Promise<IUserInfo[]>;
|
||||
/**
|
||||
* Create a new user.
|
||||
* @param username username in [\w.-]+ format.
|
||||
* @param password password at least 6 characters.
|
||||
* @param admin true | false.
|
||||
* @param email email address or empty string.
|
||||
* @param virtualCluster ["vcname1 in [A-Za-z0-9_]+ format", "vcname2 in [A-Za-z0-9_]+ format"].
|
||||
* @param extension { "extension-key1": "extension-value1" }.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
create(username: string, password: string, admin: boolean, email: string, virtualCluster: string[], extension?: {}, token?: string): Promise<any>;
|
||||
/**
|
||||
* Update user extension data.
|
||||
* @param userName The user name.
|
||||
* @param extension The new extension.
|
||||
* {
|
||||
* "extension": {
|
||||
* "key-you-wannat-add-or-update-1": "value1",
|
||||
* "key-you-wannat-add-or-update-2": {...},
|
||||
* "key-you-wannat-add-or-update-3": [...]
|
||||
* }
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
updateExtension(userName: string, extension: {}, token?: string): Promise<any>;
|
||||
/**
|
||||
* Delete a user.
|
||||
* @param userName The user name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
delete(userName: string, token?: string): Promise<any>;
|
||||
/**
|
||||
* Update user's virtual cluster.
|
||||
* @param userName The user name.
|
||||
* @param virtualCluster The new virtualCluster.
|
||||
* {
|
||||
* "virtualCluster": ["vcname1 in [A-Za-z0-9_]+ format", "vcname2 in [A-Za-z0-9_]+ format"]
|
||||
* }
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
updateVirtualcluster(userName: string, virtualCluster: string[], token?: string): Promise<any>;
|
||||
/**
|
||||
* Update user's password.
|
||||
* @param userName The user name.
|
||||
* @param oldPassword password at least 6 characters, admin could ignore this params.
|
||||
* @param newPassword password at least 6 characters.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
updatePassword(userName: string, oldPassword?: string, newPassword?: string, token?: string): Promise<any>;
|
||||
/**
|
||||
* Update user's email.
|
||||
* @param userName The user name.
|
||||
* @param email The new email.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
updateEmail(userName: string, email: string, token?: string): Promise<any>;
|
||||
/**
|
||||
* Update user's admin permission.
|
||||
* @param userName The user name.
|
||||
* @param admin true | false.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
updateAdminPermission(userName: string, admin: boolean, token?: string): Promise<any>;
|
||||
/**
|
||||
* Update user's group list.
|
||||
* @param userName The user name.
|
||||
* @param grouplist The new group list.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
updateGroupList(userName: string, grouplist: string[], token?: string): Promise<any>;
|
||||
/**
|
||||
* Add group into user's group list.
|
||||
* @param userName The user name.
|
||||
* @param groupname The new groupname in [A-Za-z0-9_]+ format.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
addGroup(userName: string, groupname: string, token?: string): Promise<any>;
|
||||
/**
|
||||
* Remove group from user's group list.
|
||||
* @param userName The user name.
|
||||
* @param groupname The groupname in [A-Za-z0-9_]+ format.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
removeGroup(userName: string, groupname: string, token?: string): Promise<any>;
|
||||
private sendPutRequestWithToken;
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const request = require("request-promise-native");
|
||||
const util_1 = require("../commom/util");
|
||||
const baseClient_1 = require("./baseClient");
|
||||
/**
|
||||
* OpenPAI User client.
|
||||
*/
|
||||
class UserClient extends baseClient_1.OpenPAIBaseClient {
|
||||
constructor(cluster) {
|
||||
super(cluster);
|
||||
}
|
||||
/**
|
||||
* Get user information.
|
||||
* @param userName The user name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async get(userName, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Get all users.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async list(token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Create a new user.
|
||||
* @param username username in [\w.-]+ format.
|
||||
* @param password password at least 6 characters.
|
||||
* @param admin true | false.
|
||||
* @param email email address or empty string.
|
||||
* @param virtualCluster ["vcname1 in [A-Za-z0-9_]+ format", "vcname2 in [A-Za-z0-9_]+ format"].
|
||||
* @param extension { "extension-key1": "extension-value1" }.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async create(username, password, admin, email, virtualCluster, extension, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.post(url, {
|
||||
body: JSON.stringify({ username, email, password, admin, virtualCluster, extension }),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Update user extension data.
|
||||
* @param userName The user name.
|
||||
* @param extension The new extension.
|
||||
* {
|
||||
* "extension": {
|
||||
* "key-you-wannat-add-or-update-1": "value1",
|
||||
* "key-you-wannat-add-or-update-2": {...},
|
||||
* "key-you-wannat-add-or-update-3": [...]
|
||||
* }
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async updateExtension(userName, extension, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/extension`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, { extension }, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Delete a user.
|
||||
* @param userName The user name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async delete(userName, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.delete(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Update user's virtual cluster.
|
||||
* @param userName The user name.
|
||||
* @param virtualCluster The new virtualCluster.
|
||||
* {
|
||||
* "virtualCluster": ["vcname1 in [A-Za-z0-9_]+ format", "vcname2 in [A-Za-z0-9_]+ format"]
|
||||
* }
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async updateVirtualcluster(userName, virtualCluster, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/virtualcluster`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, { virtualCluster }, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Update user's password.
|
||||
* @param userName The user name.
|
||||
* @param oldPassword password at least 6 characters, admin could ignore this params.
|
||||
* @param newPassword password at least 6 characters.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async updatePassword(userName, oldPassword, newPassword, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/password`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, { oldPassword, newPassword }, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Update user's email.
|
||||
* @param userName The user name.
|
||||
* @param email The new email.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async updateEmail(userName, email, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/email`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, { email }, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Update user's admin permission.
|
||||
* @param userName The user name.
|
||||
* @param admin true | false.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async updateAdminPermission(userName, admin, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/admin`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, { admin }, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Update user's group list.
|
||||
* @param userName The user name.
|
||||
* @param grouplist The new group list.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async updateGroupList(userName, grouplist, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/grouplist`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, { grouplist }, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Add group into user's group list.
|
||||
* @param userName The user name.
|
||||
* @param groupname The new groupname in [A-Za-z0-9_]+ format.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async addGroup(userName, groupname, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/group`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, { groupname }, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Remove group from user's group list.
|
||||
* @param userName The user name.
|
||||
* @param groupname The groupname in [A-Za-z0-9_]+ format.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async removeGroup(userName, groupname, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/group`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.delete(url, {
|
||||
body: JSON.stringify({ groupname }),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
async sendPutRequestWithToken(url, body, token) {
|
||||
return await request.put(url, {
|
||||
body: JSON.stringify(body),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.UserClient = UserClient;
|
|
@ -0,0 +1,47 @@
|
|||
import { IPAICluster } from '../models/cluster';
|
||||
import { INodeResource, IVirtualCluster } from '../models/virtualCluster';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
/**
|
||||
* OpenPAI Virtual Cluster client.
|
||||
*/
|
||||
export declare class VirtualClusterClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster);
|
||||
/**
|
||||
* list all virtual clusters.
|
||||
*/
|
||||
list(): Promise<{
|
||||
[id: string]: IVirtualCluster;
|
||||
}>;
|
||||
/**
|
||||
* get a virtual cluster.
|
||||
* @param vcName The name of virtual cluster.
|
||||
*/
|
||||
get(vcName: string): Promise<IVirtualCluster>;
|
||||
/**
|
||||
* get virtual cluster node resource.
|
||||
*/
|
||||
getNodeResource(): Promise<{
|
||||
[id: string]: INodeResource;
|
||||
}>;
|
||||
/**
|
||||
* Create or update a new virtual cluster.
|
||||
* @param vcName The name of the new virtual cluster.
|
||||
* @param vcCapacity The new capacity.
|
||||
* @param vcMaxCapacity The new max capacity, range of [vcCapacity, 100].
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
createOrUpdate(vcName: string, vcCapacity: number, vcMaxCapacity: number, token?: string): Promise<any>;
|
||||
/**
|
||||
* Delete a virtual cluster.
|
||||
* @param vcName The virtual cluster name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
delete(vcName: string, token?: string): Promise<any>;
|
||||
/**
|
||||
* Change a virtual cluster's status.
|
||||
* @param vcName The virtual cluster name.
|
||||
* @param vcStatus The new status 'running' | 'stopped'.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
changeStatus(vcName: string, vcStatus: 'running' | 'stopped', token?: string): Promise<any>;
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const request = require("request-promise-native");
|
||||
const util_1 = require("../commom/util");
|
||||
const baseClient_1 = require("./baseClient");
|
||||
/**
|
||||
* OpenPAI Virtual Cluster client.
|
||||
*/
|
||||
class VirtualClusterClient extends baseClient_1.OpenPAIBaseClient {
|
||||
constructor(cluster) {
|
||||
super(cluster);
|
||||
}
|
||||
/**
|
||||
* list all virtual clusters.
|
||||
*/
|
||||
async list() {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/virtual-clusters`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* get a virtual cluster.
|
||||
* @param vcName The name of virtual cluster.
|
||||
*/
|
||||
async get(vcName) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/virtual-clusters/${vcName}`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* get virtual cluster node resource.
|
||||
*/
|
||||
async getNodeResource() {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/virtual-clusters/nodeResource`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Create or update a new virtual cluster.
|
||||
* @param vcName The name of the new virtual cluster.
|
||||
* @param vcCapacity The new capacity.
|
||||
* @param vcMaxCapacity The new max capacity, range of [vcCapacity, 100].
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async createOrUpdate(vcName, vcCapacity, vcMaxCapacity, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/virtual-clusters/${vcName}`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.put(url, {
|
||||
body: JSON.stringify({ vcCapacity, vcMaxCapacity }),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Delete a virtual cluster.
|
||||
* @param vcName The virtual cluster name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async delete(vcName, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/virtual-clusters/${vcName}`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.delete(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
/**
|
||||
* Change a virtual cluster's status.
|
||||
* @param vcName The virtual cluster name.
|
||||
* @param vcStatus The new status 'running' | 'stopped'.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
async changeStatus(vcName, vcStatus, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/virtual-clusters/${vcName}/status`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.put(url, {
|
||||
body: JSON.stringify({ vcStatus }),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
}
|
||||
exports.VirtualClusterClient = VirtualClusterClient;
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* Utility class.
|
||||
*/
|
||||
declare class UtilClass {
|
||||
https: boolean;
|
||||
fixUrl(url: string, https?: boolean): string;
|
||||
}
|
||||
export declare const Util: UtilClass;
|
||||
export {};
|
|
@ -0,0 +1,33 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/**
|
||||
* Utility class.
|
||||
*/
|
||||
class UtilClass {
|
||||
constructor() {
|
||||
this.https = false;
|
||||
}
|
||||
fixUrl(url, https) {
|
||||
if (!/^[a-zA-Z]+?\:\/\//.test(url)) {
|
||||
url = `http${https ? 's' : ''}://` + url;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
||||
exports.Util = new UtilClass();
|
|
@ -0,0 +1,14 @@
|
|||
import { AuthnClient } from './client/authnClient';
|
||||
import { JobClient } from './client/jobClient';
|
||||
import { OpenPAIClient } from './client/openPAIClient';
|
||||
import { StorageClient } from './client/storageClient';
|
||||
import { UserClient } from './client/userClient';
|
||||
import { VirtualClusterClient } from './client/virtualClusterClient';
|
||||
import { IAuthnInfo, ILoginInfo } from './models/authn';
|
||||
import { IPAICluster } from './models/cluster';
|
||||
import { IJobConfig, IJobFrameworkInfo, IJobInfo, IJobSshInfo } from './models/job';
|
||||
import { IMountInfo, IStorageConfig, IStorageServer } from './models/storage';
|
||||
import { ITokenItem } from './models/token';
|
||||
import { IUserInfo } from './models/user';
|
||||
import { INodeResource, IVirtualCluster } from './models/virtualCluster';
|
||||
export { OpenPAIClient, JobClient, UserClient, VirtualClusterClient, AuthnClient, StorageClient, IPAICluster, IJobConfig, IJobInfo, IJobFrameworkInfo, IJobSshInfo, IUserInfo, ITokenItem, IVirtualCluster, INodeResource, IAuthnInfo, ILoginInfo, IStorageServer, IStorageConfig, IMountInfo };
|
|
@ -0,0 +1,30 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const authnClient_1 = require("./client/authnClient");
|
||||
exports.AuthnClient = authnClient_1.AuthnClient;
|
||||
const jobClient_1 = require("./client/jobClient");
|
||||
exports.JobClient = jobClient_1.JobClient;
|
||||
const openPAIClient_1 = require("./client/openPAIClient");
|
||||
exports.OpenPAIClient = openPAIClient_1.OpenPAIClient;
|
||||
const storageClient_1 = require("./client/storageClient");
|
||||
exports.StorageClient = storageClient_1.StorageClient;
|
||||
const userClient_1 = require("./client/userClient");
|
||||
exports.UserClient = userClient_1.UserClient;
|
||||
const virtualClusterClient_1 = require("./client/virtualClusterClient");
|
||||
exports.VirtualClusterClient = virtualClusterClient_1.VirtualClusterClient;
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* OpenPAI authn information.
|
||||
*/
|
||||
export interface IAuthnInfo {
|
||||
authn_type: string;
|
||||
loginURI: string;
|
||||
loginURIMethod: 'get' | 'post';
|
||||
}
|
||||
/**
|
||||
* OpenPAI authn basic login information.
|
||||
*/
|
||||
export interface ILoginInfo {
|
||||
admin: boolean;
|
||||
hasGitHubPAT: boolean;
|
||||
token: string;
|
||||
user: string;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* OpenPAI cluster.
|
||||
*/
|
||||
export interface IPAICluster {
|
||||
info?: IPAIClusterInfo;
|
||||
username?: string;
|
||||
password?: string;
|
||||
token?: string;
|
||||
https?: boolean;
|
||||
rest_server_uri?: string;
|
||||
webhdfs_uri?: string;
|
||||
grafana_uri?: string;
|
||||
hdfs_uri?: string;
|
||||
k8s_dashboard_uri?: string;
|
||||
web_portal_uri?: string;
|
||||
protocol_version?: string;
|
||||
}
|
||||
/**
|
||||
* OpenPAI cluster info.
|
||||
*/
|
||||
export interface IPAIClusterInfo {
|
||||
name?: string;
|
||||
version?: string;
|
||||
launcherType?: 'yarn' | 'k8s';
|
||||
authnMethod?: 'basic' | 'OIDC';
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -0,0 +1,213 @@
|
|||
/**
|
||||
* OpenPAI Job Info.
|
||||
*/
|
||||
export interface IJobInfo {
|
||||
name: string;
|
||||
username: string;
|
||||
state: 'WAITING' | 'RUNNING' | 'SUCCEEDED' | 'STOPPED' | 'FAILED' | 'UNKNOWN';
|
||||
/** raw frameworkState from frameworklauncher */
|
||||
subState: 'FRAMEWORK_COMPLETED' | 'FRAMEWORK_WAITING';
|
||||
executionType: 'START' | 'STOP';
|
||||
retries: number;
|
||||
retryDetails: {
|
||||
/** Job failed due to user or unknown error. */
|
||||
user: number;
|
||||
/** Job failed due to platform error. */
|
||||
platform: number;
|
||||
/** Job cannot get required resource to run within timeout. */
|
||||
resource: number;
|
||||
};
|
||||
createdTime: number;
|
||||
completedTime: number;
|
||||
virtualCluster: string;
|
||||
appExitCode: number;
|
||||
totalGpuNumber: number;
|
||||
totalTaskNumber: number;
|
||||
totalTaskRoleNumber: number;
|
||||
}
|
||||
/**
|
||||
* OpenPAI Job status.
|
||||
*/
|
||||
export interface IJobStatus {
|
||||
name?: string;
|
||||
jobStatus?: any | null;
|
||||
taskRoles?: any | null;
|
||||
}
|
||||
/**
|
||||
* OpenPAI Job Framework Infomation.
|
||||
*/
|
||||
export interface IJobFrameworkInfo {
|
||||
summarizedFrameworkInfo?: any | null;
|
||||
aggregatedFrameworkRequest?: any | null;
|
||||
aggregatedFrameworkStatus?: any | null;
|
||||
}
|
||||
/**
|
||||
* OpenPAI v1 job config.
|
||||
*/
|
||||
export interface IJobConfigV1 {
|
||||
jobName: string;
|
||||
image: string;
|
||||
dataDir?: string;
|
||||
authFile?: string;
|
||||
codeDir: string;
|
||||
outputDir: string;
|
||||
taskRoles: [{
|
||||
name: string;
|
||||
taskNumber: number;
|
||||
cpuNumber: number;
|
||||
gpuNumber: number;
|
||||
memoryMB: number;
|
||||
command: string;
|
||||
}];
|
||||
[key: string]: any;
|
||||
}
|
||||
/**
|
||||
* OpenPAI Job Config Protocol.
|
||||
*/
|
||||
export interface IJobConfig {
|
||||
/** Protocol version, current version is 2. */
|
||||
protocolVersion: string | number;
|
||||
name: string;
|
||||
/** Component type, should be "job" here. */
|
||||
type: string;
|
||||
/** Component version, Default is latest. */
|
||||
version?: string | number;
|
||||
contributor?: string;
|
||||
description?: string;
|
||||
/** Each item is the protocol for data, script, dockerimage, or output type. */
|
||||
prerequisites?: Array<{
|
||||
/** If omitted, follow the protocolVersion in root. */
|
||||
protocolVersion?: string | number;
|
||||
name: string;
|
||||
/** Component type. Must be one of the following: data, script, dockerimage, or output. Prerequisites.type cannot be "job". */
|
||||
type: string;
|
||||
/** Component version, Default is latest. */
|
||||
version?: string;
|
||||
contributor?: string;
|
||||
description?: string;
|
||||
/** Only available when the type is dockerimage. */
|
||||
auth?: {
|
||||
username?: string;
|
||||
/** If a password is needed, it should be referenced as a secret. */
|
||||
password?: string;
|
||||
registryuri?: string;
|
||||
};
|
||||
/** Only when the type is data can the uri be a list. */
|
||||
uri: string | string[];
|
||||
}>;
|
||||
/**
|
||||
* If specified, the whole parameters object can be referenced as `$parameters`.
|
||||
* Scope of reference `$parameters`: the reference is shared among all task roles.
|
||||
*/
|
||||
parameters?: {};
|
||||
/**
|
||||
* If sensitive information including password or API key is needed in the protocol,
|
||||
* it should be specified here in secrets section and referenced as `$secrets`.
|
||||
* Scope of reference `$secrets`: the reference is shared among all task roles and docker image's `auth` field.
|
||||
* A system that supports PAI protocol should keep the secret information away from
|
||||
* unauthorized users (how to define unauthorized user is out of the scope of this protocol).
|
||||
* For example, the yaml file used for job cloning, the stdout/stderr should protect all information marked as secrets.
|
||||
*/
|
||||
secrets?: {};
|
||||
/** Default is 0. */
|
||||
jobRetryCount?: number;
|
||||
/**
|
||||
* Task roles are different types of task in the protocol.
|
||||
* One job may have one or more task roles, each task role has one or more instances, and each instance runs inside one container.
|
||||
*/
|
||||
taskRoles: {
|
||||
/** Name of the taskRole, string in ^[A-Za-z0-9\-._~]+$ format. */
|
||||
[name: string]: {
|
||||
/** Default is 1, instances of a taskRole, no less than 1. */
|
||||
instances?: number;
|
||||
/**
|
||||
* Completion poclicy for the job, https://
|
||||
* github.com/Microsoft/pai/blob/master/subprojects/frameworklauncher/yarn/doc/USERMANUAL.md#ApplicationCompletionPolicy.
|
||||
* Number of failed tasks to fail the entire job, null or no less than 1,
|
||||
* if set to null means the job will always succeed regardless any task failure.
|
||||
*/
|
||||
completion?: {
|
||||
/**
|
||||
* Number of failed tasks to fail the entire job, null or no less than 1,
|
||||
* if set to null means the job will always succeed regardless any task failure.
|
||||
* Default is 1.
|
||||
*/
|
||||
minFailedInstances?: number | string;
|
||||
/**
|
||||
* Number of succeeded tasks to succeed the entire job, null or no less than 1,
|
||||
* if set to null means the job will only succeed until all tasks are completed and minFailedInstances is not triggered.
|
||||
* Default is null.
|
||||
*/
|
||||
minSucceededInstances?: number | string;
|
||||
};
|
||||
/** Default is 0. */
|
||||
taskRetryCount?: number;
|
||||
/** Should reference to a dockerimage defined in prerequisites. */
|
||||
dockerImage: string;
|
||||
/**
|
||||
* Scope of the reference `$data`, `$output`, `$script`: the reference is only valid inside this task role.
|
||||
* User cannot reference them from another task role. Reference for `$parameters` is global and shared among task roles.
|
||||
*/
|
||||
/** Select data defined in prerequisites, target can be referenced as `$data` in this task role. */
|
||||
data?: string;
|
||||
/** Select output defined in prerequisites, target can be referenced as `$output` in this task role. */
|
||||
output?: string;
|
||||
/** Select script defined in prerequisites, target can be referenced as `$script` in this task role. */
|
||||
script?: string;
|
||||
extraContainerOptions?: {
|
||||
/** Config the /dev/shm in a docker container, https://docs.docker.com/compose/compose-file/#shm_size. */
|
||||
shmMB?: number;
|
||||
};
|
||||
resourcePerInstance: {
|
||||
/** CPU number, unit is CPU vcore. */
|
||||
cpu: number;
|
||||
/** Memory number, unit is MB. */
|
||||
memoryMB: number;
|
||||
gpu: number;
|
||||
ports?: {
|
||||
/** Port number for the port label. Only for host network, portLabel string in ^[A-Za-z0-9\-._~]+$ format. */
|
||||
[portLabel: string]: number;
|
||||
};
|
||||
};
|
||||
commands: string[];
|
||||
};
|
||||
};
|
||||
/**
|
||||
* To handle that a component may interact with different component differently,
|
||||
* user is encouraged to place the codes handling such difference in the "deployments" field,
|
||||
* e.g., a job may get input data through wget, hdfc -dfs cp, copy, or just directly read from remote storage.
|
||||
* This logic can be placed here.
|
||||
* In summary, the deployments field is responsible to make sure the job to run properly in a deployment specific runtime environment.
|
||||
* One could have many deployments, but only one deployment can be activated at runtime by specifying in "defaults".
|
||||
* User can choose the deployment and specify in "defaults" at submission time.
|
||||
*/
|
||||
deployments?: Array<{
|
||||
name: string;
|
||||
taskRoles: {
|
||||
/** Should be in taskRoles. */
|
||||
[name: string]: {
|
||||
/** Execute before the taskRole's command. */
|
||||
preCommands: string[];
|
||||
/** Execute after the taskRole's command. */
|
||||
postCommands: string[];
|
||||
};
|
||||
};
|
||||
}>;
|
||||
/** Optional, default cluster specific settings. */
|
||||
defaults?: {
|
||||
virtualCluster?: string;
|
||||
/** Should reference to deployment defined in deployments */
|
||||
deployment?: string;
|
||||
};
|
||||
/** Optional, extra field, object, save any information that plugin may use. */
|
||||
extras?: {
|
||||
submitFrom?: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* OpenPAI Job SSH Information.
|
||||
*/
|
||||
export interface IJobSshInfo {
|
||||
containers?: any | null;
|
||||
keyPair?: any | null;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* OpenPAI storage information.
|
||||
*/
|
||||
export interface IStorageServer {
|
||||
spn: string;
|
||||
type: 'nfs' | 'samba' | 'azurefile' | 'azureblob' | 'hdfs' | 'other';
|
||||
data: {
|
||||
[prop: string]: string;
|
||||
};
|
||||
extension: any;
|
||||
}
|
||||
export interface IStorageConfig {
|
||||
name: string;
|
||||
gpn?: string;
|
||||
default: boolean;
|
||||
servers?: string[];
|
||||
mountInfos: IMountInfo[];
|
||||
}
|
||||
export interface IMountInfo {
|
||||
mountPoint: string;
|
||||
server: string;
|
||||
path: string;
|
||||
permission?: string;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* OpenPAI access token.
|
||||
*/
|
||||
export interface ITokenItem {
|
||||
token: string;
|
||||
expireTime: number;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* OpenPAI User Info.
|
||||
*/
|
||||
export interface IUserInfo {
|
||||
username?: string | null;
|
||||
grouplist?: string[] | null;
|
||||
email?: string | null;
|
||||
extension?: any | null;
|
||||
admin?: boolean;
|
||||
virtualCluster?: string[] | null;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* OpenPAI Virtual Cluster.
|
||||
*/
|
||||
export interface IVirtualCluster {
|
||||
/** capacity percentage this virtual cluster can use of entire cluster */
|
||||
capacity: number;
|
||||
/** max capacity percentage this virtual cluster can use of entire cluster */
|
||||
maxCapacity: number;
|
||||
/** used capacity percentage this virtual cluster can use of entire cluster */
|
||||
usedCapacity: number;
|
||||
numActiveJobs: number;
|
||||
numJobs: number;
|
||||
numPendingJobs: number;
|
||||
resourcesUsed: {
|
||||
memory: number;
|
||||
vCores: number;
|
||||
GPUs: number;
|
||||
};
|
||||
resourcesTotal: {
|
||||
memory: number;
|
||||
vCores: number;
|
||||
GPUs: number;
|
||||
};
|
||||
dedicated: boolean;
|
||||
/** available node list for this virtual cluster */
|
||||
nodeList: string[];
|
||||
/**
|
||||
* RUNNING: vc is enabled.
|
||||
* STOPPED: vc is disabled, without either new job or running job.
|
||||
* DRAINING: intermedia state from RUNNING to STOPPED, in waiting on existing job.
|
||||
*/
|
||||
status: 'RUNNING' | 'STOPPED' | 'DRAINING';
|
||||
}
|
||||
/**
|
||||
* OpenPAI Virtual Cluster Node Resource.
|
||||
*/
|
||||
export interface INodeResource {
|
||||
gpuTotal: number;
|
||||
gpuUsed: number;
|
||||
gpuAvaiable: number;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "openpai-js-sdk",
|
||||
"version": "0.0.0",
|
||||
"description": "The `Javascript` SDK for `OpenPAI`",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
||||
"lib/**/*"
|
||||
],
|
||||
"scripts": {
|
||||
"format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
|
||||
"lint": "tslint -p tsconfig.json",
|
||||
"test": "mocha -r ts-node/register tests/**/*.spec.ts"
|
||||
},
|
||||
"homepage": "https://github.com/Microsoft/pai",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/pai.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Microsoft/pai/issues"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Microsoft",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.2.0",
|
||||
"@types/dirty-chai": "^2.0.1",
|
||||
"@types/js-yaml": "^3.12.1",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/nock": "^10.0.3",
|
||||
"@types/request-promise-native": "^1.0.16",
|
||||
"chai": "^4.2.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"mocha": "^6.2.0",
|
||||
"nock": "^10.0.6",
|
||||
"prettier": "^1.18.2",
|
||||
"ts-node": "^8.3.0",
|
||||
"tslint": "^5.18.0",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typescript": "^3.5.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"js-yaml": "^3.13.1",
|
||||
"request": "^2.88.0",
|
||||
"request-promise-native": "^1.0.7"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as request from 'request-promise-native';
|
||||
|
||||
import { Util } from '../commom/util';
|
||||
import { IAuthnInfo, ILoginInfo } from '../models/authn';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Authn client.
|
||||
*/
|
||||
export class AuthnClient extends OpenPAIBaseClient {
|
||||
private authnInfo?: IAuthnInfo;
|
||||
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authn information.
|
||||
*/
|
||||
public async info(): Promise<IAuthnInfo> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/info`);
|
||||
if(this.authnInfo === undefined) {
|
||||
this.authnInfo = JSON.parse(await request.get(url));
|
||||
}
|
||||
|
||||
return this.authnInfo!;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenID Connect login.
|
||||
*/
|
||||
public async oidcLogin(queryString?: string): Promise<any> {
|
||||
const url = queryString ?
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/oidc/login?${queryString}`) :
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/oidc/login`);
|
||||
const res = await request.get(url);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenID Connect logout.
|
||||
*/
|
||||
public async oidcLogout(queryString?: string): Promise<any> {
|
||||
const url = queryString ?
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/oidc/logout?${queryString}`) :
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/oidc/logout`);
|
||||
const res = await request.get(url);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of available tokens (portal token + application token).
|
||||
*/
|
||||
public async getTokens(token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/token`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an application access token.
|
||||
*/
|
||||
public async createApplicationToken(token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/token/application`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.post(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a token.
|
||||
*/
|
||||
public async deleteToken(deleteToken: string, accessToken?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/token/${deleteToken}`);
|
||||
if(accessToken === undefined) {
|
||||
accessToken = await super.token();
|
||||
}
|
||||
const res = await request.delete(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as request from 'request-promise-native';
|
||||
|
||||
import { Util } from '../commom/util';
|
||||
import { ILoginInfo } from '../models/authn';
|
||||
import { IPAICluster, IPAIClusterInfo } from '../models/cluster';
|
||||
import { ITokenItem } from '../models/token';
|
||||
|
||||
/**
|
||||
* OpenPAI basic client.
|
||||
*/
|
||||
export class OpenPAIBaseClient {
|
||||
protected static readonly TIMEOUT: number = 60 * 1000;
|
||||
protected cluster: IPAICluster;
|
||||
|
||||
private cacheToken?: ITokenItem;
|
||||
|
||||
constructor(cluster: IPAICluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenPAI access token, will call /api/v1/token.
|
||||
*/
|
||||
public async token(): Promise<string> {
|
||||
if (this.cluster.token) {
|
||||
return this.cluster.token;
|
||||
} else if (!this.cacheToken || this.cacheToken.expireTime < Date.now()) {
|
||||
const res = await this.login();
|
||||
this.cacheToken = {
|
||||
expireTime: Date.now() + 3600 * 1000,
|
||||
token: res.token
|
||||
}
|
||||
}
|
||||
return this.cacheToken!.token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic login.
|
||||
*/
|
||||
public async login(): Promise<ILoginInfo> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/basic/login`);
|
||||
const res = await request.post(url, {
|
||||
form: {
|
||||
expiration: 4000,
|
||||
password: this.cluster.password,
|
||||
username: this.cluster.username
|
||||
},
|
||||
json: true,
|
||||
timeout: OpenPAIBaseClient.TIMEOUT
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenPAI cluster info, will call /api/v1.
|
||||
*/
|
||||
public async getClusterInfo(): Promise<IPAIClusterInfo> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as yaml from 'js-yaml';
|
||||
import * as request from 'request-promise-native';
|
||||
|
||||
import { Util } from '../commom/util';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { IJobConfig, IJobConfigV1, IJobFrameworkInfo, IJobInfo, IJobSshInfo, IJobStatus } from '../models/job';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Job client.
|
||||
*/
|
||||
export class JobClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster)
|
||||
}
|
||||
|
||||
/**
|
||||
* List jobs, will call /api/v1/jobs.
|
||||
* @param query The query string.
|
||||
*/
|
||||
public async list(query?: string): Promise<IJobInfo[]> {
|
||||
const url = query === undefined ?
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/jobs`) :
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/jobs?${query}`) ;
|
||||
return await request.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job status, will call /api/v2/user/{userName}/jobs/{jobName}.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
public async get(userName: string, jobName: string): Promise<IJobStatus> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/jobs/${jobName}`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a job, will call /api/v2/user/{userName}/jobs/{jobName}.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async delete(userName: string, jobName: string, token?: string): Promise<IJobStatus> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/jobs/${jobName}`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.delete(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
timeout: OpenPAIBaseClient.TIMEOUT
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job framework info, will call /api/v2/jobs/{userName}~{jobName}.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
public async getFrameworkInfo(userName: string, jobName: string): Promise<IJobFrameworkInfo> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job config, will call /api/v2/jobs/{userName}~{jobName}/config.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
public async getConfig(userName: string, jobName: string): Promise<IJobConfig> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}/config`);
|
||||
const res = await request.get(url);
|
||||
return yaml.safeLoad(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start or stop a job, will call /api/v1/user/{userName}/jobs/{jobName}/executionType.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
* @param type 'START' or 'STOP'.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async execute(userName: string, jobName: string, type: 'START' | 'STOP', token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/jobs/${jobName}/executionType`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.put(url, {
|
||||
body: JSON.stringify({
|
||||
value: type
|
||||
}),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
timeout: OpenPAIBaseClient.TIMEOUT
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a job, will call /api/v2/jobs.
|
||||
* @param jobConfig The job config.
|
||||
*/
|
||||
public async submit(jobConfig: IJobConfig, token?: string): Promise<void> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/jobs`);
|
||||
const text = yaml.safeDump(jobConfig);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
await request.post(url, {
|
||||
body: text,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'text/yaml'
|
||||
},
|
||||
timeout: OpenPAIBaseClient.TIMEOUT
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a v1 job, will call /api/v1/user/{username}/jobs.
|
||||
* @param jobConfig The job config.
|
||||
*/
|
||||
public async submitV1(userName: string, jobConfig: IJobConfigV1, token?: string): Promise<void> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/user/${userName}/jobs`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
return await request.post(url, {
|
||||
form: jobConfig,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
json: true,
|
||||
timeout: OpenPAIBaseClient.TIMEOUT
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job SSH infomation, will call /api/v1/user/${userName}/jobs/${jobName}/ssh.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
// tslint:disable-next-line: unified-signatures
|
||||
public async getSshInfo(userName: string, jobName: string): Promise<IJobSshInfo>;
|
||||
|
||||
/**
|
||||
* Get job SSH infomation, will call /api/v1/jobs/${jobName}/ssh.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
public async getSshInfo(jobName: string): Promise<IJobSshInfo>;
|
||||
|
||||
public async getSshInfo(param1: string, param2?: string): Promise<IJobSshInfo> {
|
||||
const userName = param2 ? param1 : undefined;
|
||||
const jobName = param2 ? param2 : param1;
|
||||
|
||||
const url = userName ?
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/user/${userName}/jobs/${jobName}/ssh`) :
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/jobs/${jobName}/ssh`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { AuthnClient } from '..';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
import { JobClient } from './jobClient';
|
||||
import { StorageClient } from './storageClient';
|
||||
import { UserClient} from './userClient';
|
||||
import { VirtualClusterClient } from './virtualClusterClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Client.
|
||||
*/
|
||||
export class OpenPAIClient extends OpenPAIBaseClient {
|
||||
/**
|
||||
* OpenPAI Job Client.
|
||||
*/
|
||||
public job: JobClient;
|
||||
|
||||
/**
|
||||
* OpenPAI User Client.
|
||||
*/
|
||||
public user: UserClient;
|
||||
|
||||
/**
|
||||
* OpenPAI Virtual Cluster Client.
|
||||
*/
|
||||
public virtualCluster: VirtualClusterClient;
|
||||
|
||||
/**
|
||||
* OpenPAI Authn Client.
|
||||
*/
|
||||
public authn: AuthnClient;
|
||||
|
||||
/**
|
||||
* OpenPAI Storage Client.
|
||||
*/
|
||||
public storage: StorageClient;
|
||||
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
this.job = new JobClient(cluster);
|
||||
this.user = new UserClient(cluster);
|
||||
this.virtualCluster = new VirtualClusterClient(cluster);
|
||||
this.authn = new AuthnClient(cluster);
|
||||
this.storage = new StorageClient(cluster);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { Util } from '../commom/util';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { IStorageConfig, IStorageServer } from '../models/storage';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
/**
|
||||
* OpenPAI Job client.
|
||||
*/
|
||||
export class StorageClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get storage informations.
|
||||
* @param names Filter storage server with names, default name empty will be ignored.
|
||||
*/
|
||||
public async getServer(names?: string, token?: string): Promise<IStorageServer[]> {
|
||||
const query = names ? `?names=${names}` : '';
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/server${query}`, this.cluster.https);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await axios.get<IStorageServer[]>(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get storage information.
|
||||
* @param storage The storage name.
|
||||
*/
|
||||
public async getServerByName(storage: string, token?: string): Promise<IStorageServer> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/server/${storage}`, this.cluster.https);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await axios.get<IStorageServer>(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get storage config.
|
||||
* @param names Filter storage server with names, default name empty will be ignored.
|
||||
*/
|
||||
public async getConfig(names?: string, token?: string): Promise<IStorageConfig[]> {
|
||||
const query = names ? `?names=${names}` : '';
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/config${query}`, this.cluster.https);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await axios.get<IStorageConfig[]>(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
return res.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get storage config.
|
||||
* @param storage The storage name.
|
||||
*/
|
||||
public async getConfigByName(storage: string, token?: string): Promise<IStorageConfig> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/config/${storage}`, this.cluster.https);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await axios.get<IStorageConfig>(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
return res.data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,266 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as request from 'request-promise-native';
|
||||
|
||||
import { Util } from '../commom/util';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { IUserInfo } from '../models/user';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI User client.
|
||||
*/
|
||||
export class UserClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user information.
|
||||
* @param userName The user name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async get(userName: string, token?: string): Promise<IUserInfo> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all users.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async list(token?: string): Promise<IUserInfo[]> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user.
|
||||
* @param username username in [\w.-]+ format.
|
||||
* @param password password at least 6 characters.
|
||||
* @param admin true | false.
|
||||
* @param email email address or empty string.
|
||||
* @param virtualCluster ["vcname1 in [A-Za-z0-9_]+ format", "vcname2 in [A-Za-z0-9_]+ format"].
|
||||
* @param extension { "extension-key1": "extension-value1" }.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async create(
|
||||
username: string,
|
||||
password: string,
|
||||
admin: boolean,
|
||||
email: string,
|
||||
virtualCluster: string[],
|
||||
extension?: {},
|
||||
token?: string
|
||||
): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.post(url, {
|
||||
body: JSON.stringify({username, email, password, admin, virtualCluster, extension}),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user extension data.
|
||||
* @param userName The user name.
|
||||
* @param extension The new extension.
|
||||
* {
|
||||
* "extension": {
|
||||
* "key-you-wannat-add-or-update-1": "value1",
|
||||
* "key-you-wannat-add-or-update-2": {...},
|
||||
* "key-you-wannat-add-or-update-3": [...]
|
||||
* }
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async updateExtension(userName: string, extension: {}, token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/extension`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, {extension}, token);
|
||||
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a user.
|
||||
* @param userName The user name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async delete(userName: string, token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.delete(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's virtual cluster.
|
||||
* @param userName The user name.
|
||||
* @param virtualCluster The new virtualCluster.
|
||||
* {
|
||||
* "virtualCluster": ["vcname1 in [A-Za-z0-9_]+ format", "vcname2 in [A-Za-z0-9_]+ format"]
|
||||
* }
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async updateVirtualcluster(userName: string, virtualCluster: string[], token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/virtualcluster`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, {virtualCluster}, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's password.
|
||||
* @param userName The user name.
|
||||
* @param oldPassword password at least 6 characters, admin could ignore this params.
|
||||
* @param newPassword password at least 6 characters.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async updatePassword(userName: string, oldPassword?: string, newPassword?: string, token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/password`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, {oldPassword, newPassword}, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's email.
|
||||
* @param userName The user name.
|
||||
* @param email The new email.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async updateEmail(userName: string, email: string, token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/email`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, {email}, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's admin permission.
|
||||
* @param userName The user name.
|
||||
* @param admin true | false.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async updateAdminPermission(userName: string, admin: boolean, token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/admin`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, {admin}, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's group list.
|
||||
* @param userName The user name.
|
||||
* @param grouplist The new group list.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async updateGroupList(userName: string, grouplist: string[], token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/grouplist`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, {grouplist}, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add group into user's group list.
|
||||
* @param userName The user name.
|
||||
* @param groupname The new groupname in [A-Za-z0-9_]+ format.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async addGroup(userName: string, groupname: string, token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/group`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await this.sendPutRequestWithToken(url, {groupname}, token);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove group from user's group list.
|
||||
* @param userName The user name.
|
||||
* @param groupname The groupname in [A-Za-z0-9_]+ format.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async removeGroup(userName: string, groupname: string, token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/group`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.delete(url, {
|
||||
body: JSON.stringify({groupname}),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
private async sendPutRequestWithToken(url: string, body: {}, token: string): Promise<any> {
|
||||
return await request.put(url, {
|
||||
body: JSON.stringify(body),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as request from 'request-promise-native';
|
||||
|
||||
import { Util } from '../commom/util';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { INodeResource, IVirtualCluster } from '../models/virtualCluster';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Virtual Cluster client.
|
||||
*/
|
||||
export class VirtualClusterClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster)
|
||||
}
|
||||
|
||||
/**
|
||||
* list all virtual clusters.
|
||||
*/
|
||||
public async list(): Promise<{[id: string]: IVirtualCluster}> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/virtual-clusters`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a virtual cluster.
|
||||
* @param vcName The name of virtual cluster.
|
||||
*/
|
||||
public async get(vcName: string): Promise<IVirtualCluster> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/virtual-clusters/${vcName}`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* get virtual cluster node resource.
|
||||
*/
|
||||
public async getNodeResource(): Promise<{[id: string]: INodeResource}> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/virtual-clusters/nodeResource`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or update a new virtual cluster.
|
||||
* @param vcName The name of the new virtual cluster.
|
||||
* @param vcCapacity The new capacity.
|
||||
* @param vcMaxCapacity The new max capacity, range of [vcCapacity, 100].
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async createOrUpdate(
|
||||
vcName: string,
|
||||
vcCapacity: number,
|
||||
vcMaxCapacity: number,
|
||||
token?: string
|
||||
): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/virtual-clusters/${vcName}`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.put(url, {
|
||||
body: JSON.stringify({vcCapacity, vcMaxCapacity}),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a virtual cluster.
|
||||
* @param vcName The virtual cluster name.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async delete(vcName: string, token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/virtual-clusters/${vcName}`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.delete(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a virtual cluster's status.
|
||||
* @param vcName The virtual cluster name.
|
||||
* @param vcStatus The new status 'running' | 'stopped'.
|
||||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async changeStatus(vcName: string, vcStatus: 'running' | 'stopped', token?: string): Promise<any> {
|
||||
const url = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/virtual-clusters/${vcName}/status`);
|
||||
if(token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res = await request.put(url, {
|
||||
body: JSON.stringify({vcStatus}),
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return JSON.parse(res);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
/**
|
||||
* Utility class.
|
||||
*/
|
||||
class UtilClass {
|
||||
public https: boolean = false;
|
||||
|
||||
public fixUrl(url: string, https?: boolean): string {
|
||||
if (!/^[a-zA-Z]+?\:\/\//.test(url)) {
|
||||
url = `http${https ? 's' : ''}://` + url;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
export const Util = new UtilClass();
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { AuthnClient } from './client/authnClient';
|
||||
import { JobClient } from './client/jobClient';
|
||||
import { OpenPAIClient } from './client/openPAIClient';
|
||||
import { StorageClient } from './client/storageClient';
|
||||
import { UserClient } from './client/userClient';
|
||||
import { VirtualClusterClient } from './client/virtualClusterClient';
|
||||
import { IAuthnInfo, ILoginInfo } from './models/authn';
|
||||
import { IPAICluster } from './models/cluster';
|
||||
import { IJobConfig, IJobFrameworkInfo, IJobInfo, IJobSshInfo } from './models/job';
|
||||
import { IMountInfo, IStorageConfig, IStorageServer } from './models/storage';
|
||||
import { ITokenItem } from './models/token';
|
||||
import { IUserInfo } from './models/user';
|
||||
import { INodeResource, IVirtualCluster } from './models/virtualCluster';
|
||||
|
||||
export {
|
||||
OpenPAIClient,
|
||||
JobClient,
|
||||
UserClient,
|
||||
VirtualClusterClient,
|
||||
AuthnClient,
|
||||
StorageClient,
|
||||
IPAICluster,
|
||||
IJobConfig,
|
||||
IJobInfo,
|
||||
IJobFrameworkInfo,
|
||||
IJobSshInfo,
|
||||
IUserInfo,
|
||||
ITokenItem,
|
||||
IVirtualCluster,
|
||||
INodeResource,
|
||||
IAuthnInfo,
|
||||
ILoginInfo,
|
||||
IStorageServer,
|
||||
IStorageConfig,
|
||||
IMountInfo
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
/**
|
||||
* OpenPAI authn information.
|
||||
*/
|
||||
export interface IAuthnInfo {
|
||||
authn_type: string;
|
||||
loginURI: string;
|
||||
loginURIMethod: 'get' | 'post';
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenPAI authn basic login information.
|
||||
*/
|
||||
export interface ILoginInfo {
|
||||
admin: boolean;
|
||||
hasGitHubPAT: boolean;
|
||||
token: string;
|
||||
user: string;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
/**
|
||||
* OpenPAI cluster.
|
||||
*/
|
||||
export interface IPAICluster {
|
||||
info?: IPAIClusterInfo;
|
||||
username?: string;
|
||||
password?: string;
|
||||
token?: string;
|
||||
https?: boolean;
|
||||
rest_server_uri?: string;
|
||||
webhdfs_uri?: string;
|
||||
grafana_uri?: string;
|
||||
hdfs_uri?: string;
|
||||
k8s_dashboard_uri?: string;
|
||||
web_portal_uri?: string;
|
||||
protocol_version?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenPAI cluster info.
|
||||
*/
|
||||
export interface IPAIClusterInfo {
|
||||
name?: string;
|
||||
version?: string;
|
||||
launcherType?: 'yarn' | 'k8s';
|
||||
authnMethod?: 'basic' | 'OIDC';
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
/**
|
||||
* OpenPAI Job Info.
|
||||
*/
|
||||
export interface IJobInfo {
|
||||
name: string;
|
||||
username: string;
|
||||
state: 'WAITING' | 'RUNNING' | 'SUCCEEDED' | 'STOPPED' | 'FAILED' | 'UNKNOWN';
|
||||
/** raw frameworkState from frameworklauncher */
|
||||
subState: 'FRAMEWORK_COMPLETED' | 'FRAMEWORK_WAITING';
|
||||
executionType: 'START' | 'STOP';
|
||||
retries: number;
|
||||
retryDetails: {
|
||||
/** Job failed due to user or unknown error. */
|
||||
user: number,
|
||||
/** Job failed due to platform error. */
|
||||
platform: number,
|
||||
/** Job cannot get required resource to run within timeout. */
|
||||
resource: number
|
||||
};
|
||||
createdTime: number;
|
||||
completedTime: number;
|
||||
virtualCluster: string;
|
||||
appExitCode: number;
|
||||
totalGpuNumber: number;
|
||||
totalTaskNumber: number;
|
||||
totalTaskRoleNumber: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenPAI Job status.
|
||||
*/
|
||||
export interface IJobStatus {
|
||||
name?: string;
|
||||
jobStatus?: any | null;
|
||||
taskRoles?: any | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenPAI Job Framework Infomation.
|
||||
*/
|
||||
export interface IJobFrameworkInfo {
|
||||
summarizedFrameworkInfo?: any | null;
|
||||
aggregatedFrameworkRequest?: any | null;
|
||||
aggregatedFrameworkStatus?: any | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenPAI v1 job config.
|
||||
*/
|
||||
export interface IJobConfigV1 {
|
||||
jobName: string;
|
||||
image: string;
|
||||
dataDir?: string;
|
||||
authFile?: string;
|
||||
codeDir: string;
|
||||
outputDir: string;
|
||||
taskRoles: [{
|
||||
name: string;
|
||||
taskNumber: number;
|
||||
cpuNumber: number;
|
||||
gpuNumber: number;
|
||||
memoryMB: number;
|
||||
command: string;
|
||||
}];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenPAI Job Config Protocol.
|
||||
*/
|
||||
export interface IJobConfig {
|
||||
/** Protocol version, current version is 2. */
|
||||
protocolVersion: string | number;
|
||||
name: string;
|
||||
/** Component type, should be "job" here. */
|
||||
type: string;
|
||||
/** Component version, Default is latest. */
|
||||
version?: string | number;
|
||||
contributor?: string;
|
||||
description?: string;
|
||||
|
||||
/** Each item is the protocol for data, script, dockerimage, or output type. */
|
||||
prerequisites?: Array<{
|
||||
/** If omitted, follow the protocolVersion in root. */
|
||||
protocolVersion?: string | number;
|
||||
name: string;
|
||||
/** Component type. Must be one of the following: data, script, dockerimage, or output. Prerequisites.type cannot be "job". */
|
||||
type: string;
|
||||
/** Component version, Default is latest. */
|
||||
version?: string;
|
||||
contributor?: string;
|
||||
description?: string;
|
||||
/** Only available when the type is dockerimage. */
|
||||
auth?: {
|
||||
username?: string;
|
||||
/** If a password is needed, it should be referenced as a secret. */
|
||||
password?: string;
|
||||
registryuri?: string;
|
||||
};
|
||||
/** Only when the type is data can the uri be a list. */
|
||||
uri: string | string[];
|
||||
}>;
|
||||
|
||||
/**
|
||||
* If specified, the whole parameters object can be referenced as `$parameters`.
|
||||
* Scope of reference `$parameters`: the reference is shared among all task roles.
|
||||
*/
|
||||
parameters?: {
|
||||
/**
|
||||
* <param1>: value1
|
||||
* <param2>: value2
|
||||
* Specify name and value of all the referencable parameters that will be used in the whole job template.
|
||||
* Can be referenced by `<% $parameters.param1 %>`, `<% $parameters.param2 %>`.
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* If sensitive information including password or API key is needed in the protocol,
|
||||
* it should be specified here in secrets section and referenced as `$secrets`.
|
||||
* Scope of reference `$secrets`: the reference is shared among all task roles and docker image's `auth` field.
|
||||
* A system that supports PAI protocol should keep the secret information away from
|
||||
* unauthorized users (how to define unauthorized user is out of the scope of this protocol).
|
||||
* For example, the yaml file used for job cloning, the stdout/stderr should protect all information marked as secrets.
|
||||
*/
|
||||
secrets?: {
|
||||
/**
|
||||
* <secret1>: password
|
||||
* <secret2>: key
|
||||
* Specify name and value of all secrets that will be used in the whole job template.
|
||||
* Can be referenced by `<% $secrets.secret1 %>`, `<% $secrets.secret2 %>`.
|
||||
*/
|
||||
};
|
||||
|
||||
/** Default is 0. */
|
||||
jobRetryCount?: number;
|
||||
|
||||
/**
|
||||
* Task roles are different types of task in the protocol.
|
||||
* One job may have one or more task roles, each task role has one or more instances, and each instance runs inside one container.
|
||||
*/
|
||||
taskRoles: {
|
||||
/** Name of the taskRole, string in ^[A-Za-z0-9\-._~]+$ format. */
|
||||
[name: string]: {
|
||||
/** Default is 1, instances of a taskRole, no less than 1. */
|
||||
instances?: number;
|
||||
/**
|
||||
* Completion poclicy for the job, https://
|
||||
* github.com/Microsoft/pai/blob/master/subprojects/frameworklauncher/yarn/doc/USERMANUAL.md#ApplicationCompletionPolicy.
|
||||
* Number of failed tasks to fail the entire job, null or no less than 1,
|
||||
* if set to null means the job will always succeed regardless any task failure.
|
||||
*/
|
||||
completion?: {
|
||||
/**
|
||||
* Number of failed tasks to fail the entire job, null or no less than 1,
|
||||
* if set to null means the job will always succeed regardless any task failure.
|
||||
* Default is 1.
|
||||
*/
|
||||
minFailedInstances?: number | string;
|
||||
/**
|
||||
* Number of succeeded tasks to succeed the entire job, null or no less than 1,
|
||||
* if set to null means the job will only succeed until all tasks are completed and minFailedInstances is not triggered.
|
||||
* Default is null.
|
||||
*/
|
||||
minSucceededInstances?: number | string;
|
||||
};
|
||||
/** Default is 0. */
|
||||
taskRetryCount?: number;
|
||||
/** Should reference to a dockerimage defined in prerequisites. */
|
||||
dockerImage: string;
|
||||
/**
|
||||
* Scope of the reference `$data`, `$output`, `$script`: the reference is only valid inside this task role.
|
||||
* User cannot reference them from another task role. Reference for `$parameters` is global and shared among task roles.
|
||||
*/
|
||||
/** Select data defined in prerequisites, target can be referenced as `$data` in this task role. */
|
||||
data?: string;
|
||||
/** Select output defined in prerequisites, target can be referenced as `$output` in this task role. */
|
||||
output?: string;
|
||||
/** Select script defined in prerequisites, target can be referenced as `$script` in this task role. */
|
||||
script?: string;
|
||||
|
||||
extraContainerOptions?: {
|
||||
/** Config the /dev/shm in a docker container, https://docs.docker.com/compose/compose-file/#shm_size. */
|
||||
shmMB?: number;
|
||||
};
|
||||
|
||||
resourcePerInstance: {
|
||||
/** CPU number, unit is CPU vcore. */
|
||||
cpu: number;
|
||||
/** Memory number, unit is MB. */
|
||||
memoryMB: number;
|
||||
gpu: number;
|
||||
ports?: {
|
||||
/** Port number for the port label. Only for host network, portLabel string in ^[A-Za-z0-9\-._~]+$ format. */
|
||||
[portLabel: string]: number;
|
||||
}
|
||||
};
|
||||
|
||||
commands: string[];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* To handle that a component may interact with different component differently,
|
||||
* user is encouraged to place the codes handling such difference in the "deployments" field,
|
||||
* e.g., a job may get input data through wget, hdfc -dfs cp, copy, or just directly read from remote storage.
|
||||
* This logic can be placed here.
|
||||
* In summary, the deployments field is responsible to make sure the job to run properly in a deployment specific runtime environment.
|
||||
* One could have many deployments, but only one deployment can be activated at runtime by specifying in "defaults".
|
||||
* User can choose the deployment and specify in "defaults" at submission time.
|
||||
*/
|
||||
deployments?: Array<{
|
||||
name: string;
|
||||
taskRoles: {
|
||||
/** Should be in taskRoles. */
|
||||
[name: string]: {
|
||||
/** Execute before the taskRole's command. */
|
||||
preCommands: string[];
|
||||
/** Execute after the taskRole's command. */
|
||||
postCommands: string[];
|
||||
}
|
||||
}
|
||||
}>;
|
||||
|
||||
/** Optional, default cluster specific settings. */
|
||||
defaults?: {
|
||||
virtualCluster?: string;
|
||||
/** Should reference to deployment defined in deployments */
|
||||
deployment?: string;
|
||||
};
|
||||
|
||||
/** Optional, extra field, object, save any information that plugin may use. */
|
||||
extras?: {
|
||||
submitFrom?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenPAI Job SSH Information.
|
||||
*/
|
||||
export interface IJobSshInfo {
|
||||
containers?: any | null;
|
||||
keyPair?: any | null;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
/**
|
||||
* OpenPAI storage information.
|
||||
*/
|
||||
export interface IStorageServer {
|
||||
spn: string;
|
||||
type: 'nfs' | 'samba' | 'azurefile' | 'azureblob' | 'hdfs' | 'other';
|
||||
data: {
|
||||
[prop: string]: string;
|
||||
};
|
||||
extension: any;
|
||||
}
|
||||
|
||||
export interface IStorageConfig {
|
||||
name: string;
|
||||
gpn?: string;
|
||||
default: boolean;
|
||||
servers?: string[];
|
||||
mountInfos: IMountInfo[];
|
||||
}
|
||||
|
||||
export interface IMountInfo {
|
||||
mountPoint: string;
|
||||
server: string;
|
||||
path: string;
|
||||
permission?: string;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
/**
|
||||
* OpenPAI access token.
|
||||
*/
|
||||
export interface ITokenItem {
|
||||
token: string;
|
||||
expireTime: number;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
/**
|
||||
* OpenPAI User Info.
|
||||
*/
|
||||
export interface IUserInfo {
|
||||
username?: string | null,
|
||||
grouplist?: string[] | null,
|
||||
email?: string | null,
|
||||
extension?: any | null,
|
||||
admin?: boolean,
|
||||
virtualCluster?: string[] | null
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
/**
|
||||
* OpenPAI Virtual Cluster.
|
||||
*/
|
||||
export interface IVirtualCluster {
|
||||
/** capacity percentage this virtual cluster can use of entire cluster */
|
||||
capacity: number;
|
||||
|
||||
/** max capacity percentage this virtual cluster can use of entire cluster */
|
||||
maxCapacity: number;
|
||||
|
||||
/** used capacity percentage this virtual cluster can use of entire cluster */
|
||||
usedCapacity: number;
|
||||
numActiveJobs: number;
|
||||
numJobs: number;
|
||||
numPendingJobs: number;
|
||||
resourcesUsed: {
|
||||
memory: number;
|
||||
vCores: number;
|
||||
GPUs: number;
|
||||
};
|
||||
resourcesTotal: {
|
||||
memory: number;
|
||||
vCores: number;
|
||||
GPUs: number;
|
||||
};
|
||||
dedicated: boolean;
|
||||
|
||||
/** available node list for this virtual cluster */
|
||||
nodeList: string[];
|
||||
|
||||
/**
|
||||
* RUNNING: vc is enabled.
|
||||
* STOPPED: vc is disabled, without either new job or running job.
|
||||
* DRAINING: intermedia state from RUNNING to STOPPED, in waiting on existing job.
|
||||
*/
|
||||
status: 'RUNNING' | 'STOPPED' | 'DRAINING';
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenPAI Virtual Cluster Node Resource.
|
||||
*/
|
||||
export interface INodeResource {
|
||||
gpuTotal: number;
|
||||
gpuUsed: number;
|
||||
gpuAvaiable: number;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { IUserInfo } from '../../../src/models/user';
|
||||
|
||||
export const testAllUsers: IUserInfo[] = [{
|
||||
"username": "core",
|
||||
"grouplist": [
|
||||
"adminGroup",
|
||||
"default",
|
||||
"admingroup"
|
||||
],
|
||||
"email": "",
|
||||
"extension": {
|
||||
"virtualCluster": [
|
||||
"default"
|
||||
]
|
||||
},
|
||||
"admin": true,
|
||||
"virtualCluster": [
|
||||
"default"
|
||||
]
|
||||
}];
|
|
@ -0,0 +1,378 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { IVirtualCluster } from '../../../src/models/virtualCluster';
|
||||
|
||||
export const testAllVirtualClusters: { [id: string]: IVirtualCluster } = {
|
||||
"default": {
|
||||
"capacity": 26.481485,
|
||||
"maxCapacity": 100,
|
||||
"usedCapacity": 5.555556,
|
||||
"numActiveJobs": 3,
|
||||
"numJobs": 3,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 27648,
|
||||
"vCores": 15,
|
||||
"GPUs": 3
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": false,
|
||||
"resourcesTotal": {
|
||||
"vCores": 85.8000114,
|
||||
"memory": 740295.209472,
|
||||
"GPUs": 14.3000019
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.35",
|
||||
"0.0.0.26",
|
||||
"0.0.0.39",
|
||||
"0.0.0.42",
|
||||
"0.0.0.27",
|
||||
"0.0.0.36",
|
||||
"0.0.0.28",
|
||||
"0.0.0.33",
|
||||
"0.0.0.24",
|
||||
"0.0.0.29",
|
||||
"0.0.0.37",
|
||||
"0.0.0.41",
|
||||
"0.0.0.32",
|
||||
"0.0.0.38",
|
||||
"0.0.0.40"
|
||||
]
|
||||
},
|
||||
"vc2": {
|
||||
"capacity": 22.962963,
|
||||
"maxCapacity": 22.962963,
|
||||
"usedCapacity": 0,
|
||||
"numActiveJobs": 0,
|
||||
"numJobs": 0,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 0,
|
||||
"vCores": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": false,
|
||||
"resourcesTotal": {
|
||||
"vCores": 74.40000012,
|
||||
"memory": 641934.2232575999,
|
||||
"GPUs": 12.40000002
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.35",
|
||||
"0.0.0.26",
|
||||
"0.0.0.39",
|
||||
"0.0.0.42",
|
||||
"0.0.0.27",
|
||||
"0.0.0.36",
|
||||
"0.0.0.28",
|
||||
"0.0.0.33",
|
||||
"0.0.0.24",
|
||||
"0.0.0.29",
|
||||
"0.0.0.37",
|
||||
"0.0.0.41",
|
||||
"0.0.0.32",
|
||||
"0.0.0.38",
|
||||
"0.0.0.40"
|
||||
]
|
||||
},
|
||||
"vc1": {
|
||||
"capacity": 17.222221,
|
||||
"maxCapacity": 17.222221,
|
||||
"usedCapacity": 0,
|
||||
"numActiveJobs": 0,
|
||||
"numJobs": 0,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 0,
|
||||
"vCores": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": false,
|
||||
"resourcesTotal": {
|
||||
"vCores": 55.79999604,
|
||||
"memory": 481450.63249920008,
|
||||
"GPUs": 9.299999340000002
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.35",
|
||||
"0.0.0.26",
|
||||
"0.0.0.39",
|
||||
"0.0.0.42",
|
||||
"0.0.0.27",
|
||||
"0.0.0.36",
|
||||
"0.0.0.28",
|
||||
"0.0.0.33",
|
||||
"0.0.0.24",
|
||||
"0.0.0.29",
|
||||
"0.0.0.37",
|
||||
"0.0.0.41",
|
||||
"0.0.0.32",
|
||||
"0.0.0.38",
|
||||
"0.0.0.40"
|
||||
]
|
||||
},
|
||||
"test11": {
|
||||
"capacity": 5.740741,
|
||||
"maxCapacity": 5.740741,
|
||||
"usedCapacity": 0,
|
||||
"numActiveJobs": 0,
|
||||
"numJobs": 0,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 0,
|
||||
"vCores": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": false,
|
||||
"resourcesTotal": {
|
||||
"vCores": 18.60000084,
|
||||
"memory": 160483.5628032,
|
||||
"GPUs": 3.1000001399999999
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.35",
|
||||
"0.0.0.26",
|
||||
"0.0.0.39",
|
||||
"0.0.0.42",
|
||||
"0.0.0.27",
|
||||
"0.0.0.36",
|
||||
"0.0.0.28",
|
||||
"0.0.0.33",
|
||||
"0.0.0.24",
|
||||
"0.0.0.29",
|
||||
"0.0.0.37",
|
||||
"0.0.0.41",
|
||||
"0.0.0.32",
|
||||
"0.0.0.38",
|
||||
"0.0.0.40"
|
||||
]
|
||||
},
|
||||
"test_vc_1": {
|
||||
"capacity": 100,
|
||||
"maxCapacity": 100,
|
||||
"usedCapacity": 0,
|
||||
"numActiveJobs": 0,
|
||||
"numJobs": 0,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 0,
|
||||
"vCores": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": true,
|
||||
"resourcesTotal": {
|
||||
"vCores": 48,
|
||||
"memory": 417792,
|
||||
"GPUs": 8
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.30",
|
||||
"0.0.0.31"
|
||||
]
|
||||
},
|
||||
"nni": {
|
||||
"capacity": 11.481482,
|
||||
"maxCapacity": 11.481482,
|
||||
"usedCapacity": 0,
|
||||
"numActiveJobs": 0,
|
||||
"numJobs": 0,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 0,
|
||||
"vCores": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": false,
|
||||
"resourcesTotal": {
|
||||
"vCores": 37.20000168,
|
||||
"memory": 320967.1256064,
|
||||
"GPUs": 6.200000279999999
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.35",
|
||||
"0.0.0.26",
|
||||
"0.0.0.39",
|
||||
"0.0.0.42",
|
||||
"0.0.0.27",
|
||||
"0.0.0.36",
|
||||
"0.0.0.28",
|
||||
"0.0.0.33",
|
||||
"0.0.0.24",
|
||||
"0.0.0.29",
|
||||
"0.0.0.37",
|
||||
"0.0.0.41",
|
||||
"0.0.0.32",
|
||||
"0.0.0.38",
|
||||
"0.0.0.40"
|
||||
]
|
||||
},
|
||||
"testvc": {
|
||||
"capacity": 5.3703694,
|
||||
"maxCapacity": 5.3703694,
|
||||
"usedCapacity": 0,
|
||||
"numActiveJobs": 0,
|
||||
"numJobs": 0,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 0,
|
||||
"vCores": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": false,
|
||||
"resourcesTotal": {
|
||||
"vCores": 17.399996856,
|
||||
"memory": 150129.75065088,
|
||||
"GPUs": 2.8999994760000007
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.35",
|
||||
"0.0.0.26",
|
||||
"0.0.0.39",
|
||||
"0.0.0.42",
|
||||
"0.0.0.27",
|
||||
"0.0.0.36",
|
||||
"0.0.0.28",
|
||||
"0.0.0.33",
|
||||
"0.0.0.24",
|
||||
"0.0.0.29",
|
||||
"0.0.0.37",
|
||||
"0.0.0.41",
|
||||
"0.0.0.32",
|
||||
"0.0.0.38",
|
||||
"0.0.0.40"
|
||||
]
|
||||
},
|
||||
"newtest": {
|
||||
"capacity": 0,
|
||||
"maxCapacity": 0,
|
||||
"usedCapacity": 0,
|
||||
"numActiveJobs": 0,
|
||||
"numJobs": 0,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 0,
|
||||
"vCores": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": false,
|
||||
"resourcesTotal": {
|
||||
"vCores": 0,
|
||||
"memory": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.35",
|
||||
"0.0.0.26",
|
||||
"0.0.0.39",
|
||||
"0.0.0.42",
|
||||
"0.0.0.27",
|
||||
"0.0.0.36",
|
||||
"0.0.0.28",
|
||||
"0.0.0.33",
|
||||
"0.0.0.24",
|
||||
"0.0.0.29",
|
||||
"0.0.0.37",
|
||||
"0.0.0.41",
|
||||
"0.0.0.32",
|
||||
"0.0.0.38",
|
||||
"0.0.0.40"
|
||||
]
|
||||
},
|
||||
"test_new": {
|
||||
"capacity": 0,
|
||||
"maxCapacity": 0,
|
||||
"usedCapacity": 0,
|
||||
"numActiveJobs": 0,
|
||||
"numJobs": 0,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 0,
|
||||
"vCores": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": false,
|
||||
"resourcesTotal": {
|
||||
"vCores": 0,
|
||||
"memory": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.35",
|
||||
"0.0.0.26",
|
||||
"0.0.0.39",
|
||||
"0.0.0.42",
|
||||
"0.0.0.27",
|
||||
"0.0.0.36",
|
||||
"0.0.0.28",
|
||||
"0.0.0.33",
|
||||
"0.0.0.24",
|
||||
"0.0.0.29",
|
||||
"0.0.0.37",
|
||||
"0.0.0.41",
|
||||
"0.0.0.32",
|
||||
"0.0.0.38",
|
||||
"0.0.0.40"
|
||||
]
|
||||
},
|
||||
"wertwer": {
|
||||
"capacity": 10.740738,
|
||||
"maxCapacity": 10.740738,
|
||||
"usedCapacity": 0,
|
||||
"numActiveJobs": 0,
|
||||
"numJobs": 0,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 0,
|
||||
"vCores": 0,
|
||||
"GPUs": 0
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": false,
|
||||
"resourcesTotal": {
|
||||
"vCores": 34.79999112,
|
||||
"memory": 300259.4789376,
|
||||
"GPUs": 5.79999852
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.35",
|
||||
"0.0.0.26",
|
||||
"0.0.0.39",
|
||||
"0.0.0.42",
|
||||
"0.0.0.27",
|
||||
"0.0.0.36",
|
||||
"0.0.0.28",
|
||||
"0.0.0.33",
|
||||
"0.0.0.24",
|
||||
"0.0.0.29",
|
||||
"0.0.0.37",
|
||||
"0.0.0.41",
|
||||
"0.0.0.32",
|
||||
"0.0.0.38",
|
||||
"0.0.0.40"
|
||||
]
|
||||
}
|
||||
};
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { IJobConfig, IJobConfigV1 } from '../../../src/models/job';
|
||||
|
||||
export const testJobConfig: IJobConfig = {
|
||||
"contributor": "OpenPAI",
|
||||
"description": "# Serving a TensorFlow MNIST Digit Recognition Model\n" +
|
||||
"This example shows you how to use TensorFlow Serving components to export a trained TensorFlow model\n" +
|
||||
"and use the standard tensorflow_model_server to serve it on OpenPAI.\n" +
|
||||
"This example uses the simple Softmax Regression model introduced in the TensorFlow tutorial for handwritten image (MNIST data) classification.\n" +
|
||||
"Reference https://www.tensorflow.org/tfx/serving/serving_basic.\n",
|
||||
"name": "tensorflow_serving_mnist_2019_6585ba19_test",
|
||||
"parameters": {
|
||||
"modelPath": "/tmp/mnist_model"
|
||||
},
|
||||
"prerequisites": [
|
||||
{
|
||||
"contributor": "OpenPAI",
|
||||
"description": "This is an [example TensorFlow Serving Docker image on OpenPAI](https://github.com/Microsoft/pai/tree/master/examples/serving).\n",
|
||||
"name": "tf_serving_example",
|
||||
"protocolVersion": 2,
|
||||
"type": "dockerimage",
|
||||
"uri": "openpai/pai.example.tensorflow-serving",
|
||||
"version": "1.0-r1.4"
|
||||
}
|
||||
],
|
||||
"protocolVersion": 2,
|
||||
"taskRoles": {
|
||||
"worker": {
|
||||
"commands": [
|
||||
"bazel-bin/tensorflow_serving/example/mnist_saved_model <% $parameters.modelPath %>",
|
||||
"tensorflow_model_server --port=$PAI_CONTAINER_HOST_model_server_PORT_LIST --model_name=mnist --model_base_path=<% $parameters.modelPath %>"
|
||||
],
|
||||
"dockerImage": "tf_serving_example",
|
||||
"instances": 1,
|
||||
"resourcePerInstance": {
|
||||
"cpu": 4,
|
||||
"gpu": 1,
|
||||
"memoryMB": 8192,
|
||||
"ports": {
|
||||
"model_server": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "job",
|
||||
"version": 1
|
||||
};
|
||||
|
||||
export const testJobConfigV1: IJobConfigV1 = {
|
||||
// Name for the job, need to be unique
|
||||
"jobName": "test_job_20190819",
|
||||
|
||||
// URL pointing to the Docker image for all tasks in the job
|
||||
"image": "aiplatform/pai.build.base",
|
||||
|
||||
// Code directory existing on HDFS.
|
||||
// Full HDFS path will be exported as an environment variable $PAI_CODE_DIR.
|
||||
"codeDir": "$PAI_DEFAULT_FS_URI/$PAI_USER_NAME/$PAI_JOB_NAME",
|
||||
|
||||
// Data directory existing on HDFS.
|
||||
// Full HDFS path will be exported as an environment variable $PAI_DATA_DIR.
|
||||
"dataDir": "$PAI_DEFAULT_FS_URI/Data/$PAI_JOB_NAME",
|
||||
|
||||
// Output directory on HDFS, $PAI_DEFAULT_FS_URI/Output/$jobName will be used if
|
||||
// not specified.
|
||||
// Full HDFS path will be exported as an environment variable $PAI_OUTPUT_DIR.
|
||||
"outputDir": "$PAI_DEFAULT_FS_URI/Output/$PAI_JOB_NAME",
|
||||
|
||||
// List of taskRole, one task role at least
|
||||
"taskRoles": [
|
||||
{
|
||||
// Name for the task role, need to be unique with other roles
|
||||
"name": "task",
|
||||
|
||||
// Number of tasks for the task role, no less than 1
|
||||
"taskNumber": 1,
|
||||
|
||||
// CPU number for one task in the task role, no less than 1
|
||||
"cpuNumber": 1,
|
||||
|
||||
// GPU number for one task in the task role, no less than 0
|
||||
"gpuNumber": 0,
|
||||
|
||||
// Memory for one task in the task role, no less than 100
|
||||
"memoryMB": 1000,
|
||||
|
||||
// Executable command for tasks in the task role, can not be empty
|
||||
// ** PLEASE CHANGE MANUALLY **
|
||||
"command": "python $PAI_JOB_NAME/<start up script>"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { IJobFrameworkInfo } from '../../../src/models/job';
|
||||
|
||||
export const testJobFrameworkInfo: IJobFrameworkInfo = {
|
||||
"summarizedFrameworkInfo": {
|
||||
"frameworkName": "core~tensorflow_serving_mnist_2019_6585ba19",
|
||||
"frameworkVersion": 10,
|
||||
"executionType": "START",
|
||||
"frameworkDescription": null,
|
||||
"userName": "core",
|
||||
"queue": "default",
|
||||
"totalGpuNumber": 1,
|
||||
"totalTaskNumber": 1,
|
||||
"totalTaskRoleNumber": 1,
|
||||
"firstRequestTimestamp": 1565329763372,
|
||||
"lastRequestTimestamp": 1565329763372,
|
||||
"frameworkState": "APPLICATION_RUNNING",
|
||||
"frameworkRetryPolicyState": {
|
||||
"retriedCount": 0,
|
||||
"succeededRetriedCount": 0,
|
||||
"transientNormalRetriedCount": 1,
|
||||
"transientConflictRetriedCount": 0,
|
||||
"nonTransientRetriedCount": 0,
|
||||
"unKnownRetriedCount": 0
|
||||
},
|
||||
"frameworkCompletedTimestamp": null,
|
||||
"applicationExitCode": null
|
||||
},
|
||||
"aggregatedFrameworkRequest": {
|
||||
"frameworkRequest": {
|
||||
"frameworkName": "core~tensorflow_serving_mnist_2019_6585ba19",
|
||||
"frameworkDescriptor": {
|
||||
"description": null,
|
||||
"version": 10,
|
||||
"executionType": "START",
|
||||
"retryPolicy": {
|
||||
"fancyRetryPolicy": true,
|
||||
"maxRetryCount": 0
|
||||
},
|
||||
"parentFramework": null,
|
||||
"user": {
|
||||
"name": "core"
|
||||
},
|
||||
"taskRoles": {
|
||||
"worker": {
|
||||
"taskNumber": 1,
|
||||
"scaleUnitNumber": 1,
|
||||
"scaleUnitTimeoutSec": 0,
|
||||
"taskRetryPolicy": {
|
||||
"fancyRetryPolicy": false,
|
||||
"maxRetryCount": 0
|
||||
},
|
||||
"applicationCompletionPolicy": {
|
||||
"minFailedTaskCount": 1,
|
||||
"minSucceededTaskCount": null
|
||||
},
|
||||
"taskService": {
|
||||
"version": 0,
|
||||
"entryPoint": "source YarnContainerScripts/worker.sh",
|
||||
"sourceLocations": [
|
||||
"/Container/core/core~tensorflow_serving_mnist_2019_6585ba19/YarnContainerScripts"
|
||||
],
|
||||
"resource": {
|
||||
"cpuNumber": 4,
|
||||
"memoryMB": 8192,
|
||||
"portDefinitions": {
|
||||
"ssh": {
|
||||
"start": 0,
|
||||
"count": 1
|
||||
},
|
||||
"http": {
|
||||
"start": 0,
|
||||
"count": 1
|
||||
},
|
||||
"model_server": {
|
||||
"start": 0,
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"diskType": "HDD",
|
||||
"diskMB": 0,
|
||||
"gpuNumber": 1,
|
||||
"gpuAttribute": 0
|
||||
}
|
||||
},
|
||||
"platformSpecificParameters": {
|
||||
"taskNodeLabel": null,
|
||||
"taskNodeGpuType": null,
|
||||
"samePortAllocation": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"platformSpecificParameters": {
|
||||
"amResource": {
|
||||
"cpuNumber": 1,
|
||||
"memoryMB": 1024,
|
||||
"portDefinitions": {},
|
||||
"diskType": "HDD",
|
||||
"diskMB": 0,
|
||||
"gpuNumber": 0,
|
||||
"gpuAttribute": 0
|
||||
},
|
||||
"amNodeLabel": null,
|
||||
"taskNodeLabel": null,
|
||||
"taskNodeGpuType": null,
|
||||
"queue": "default",
|
||||
"containerConnectionMaxLostCount": -2,
|
||||
"containerConnectionMaxExceedCount": 2,
|
||||
"antiaffinityAllocation": false,
|
||||
"gangAllocation": true,
|
||||
"skipLocalTriedResource": true,
|
||||
"amType": "DEFAULT",
|
||||
"agentUseHeartbeat": false,
|
||||
"agentHeartbeatIntervalSec": 30,
|
||||
"agentExpiryIntervalSec": 180,
|
||||
"agentUseHealthCheck": false,
|
||||
"taskServiceHealthCheck": null
|
||||
}
|
||||
},
|
||||
"launchClientType": "UNKNOWN",
|
||||
"launchClientHostName": "172.17.0.2",
|
||||
"launchClientUserName": "UNKNOWN",
|
||||
"firstRequestTimestamp": 1565329763372,
|
||||
"lastRequestTimestamp": 1565329763372
|
||||
},
|
||||
"overrideApplicationProgressRequest": null,
|
||||
"migrateTaskRequests": {}
|
||||
},
|
||||
"aggregatedFrameworkStatus": {
|
||||
"frameworkStatus": {
|
||||
"frameworkName": "core~tensorflow_serving_mnist_2019_6585ba19",
|
||||
"frameworkVersion": 10,
|
||||
"frameworkState": "APPLICATION_RUNNING",
|
||||
"frameworkRetryPolicyState": {
|
||||
"retriedCount": 0,
|
||||
"succeededRetriedCount": 0,
|
||||
"transientNormalRetriedCount": 1,
|
||||
"transientConflictRetriedCount": 0,
|
||||
"nonTransientRetriedCount": 0,
|
||||
"unKnownRetriedCount": 0
|
||||
},
|
||||
"frameworkCreatedTimestamp": 1565329763372,
|
||||
"frameworkCompletedTimestamp": null,
|
||||
"applicationId": "application_1565337391589_0002",
|
||||
"applicationProgress": 0,
|
||||
"applicationTrackingUrl": "http://0.0.0.34:8088/proxy/application_1565337391589_0002/",
|
||||
"applicationLaunchedTimestamp": 1565337476313,
|
||||
"applicationCompletedTimestamp": null,
|
||||
"applicationExitCode": null,
|
||||
"applicationExitDescription": null,
|
||||
"applicationExitDiagnostics": null,
|
||||
"applicationExitType": null,
|
||||
"applicationExitTriggerMessage": null,
|
||||
"applicationExitTriggerTaskRoleName": null,
|
||||
"applicationExitTriggerTaskIndex": null
|
||||
},
|
||||
"aggregatedTaskRoleStatuses": {
|
||||
"worker": {
|
||||
"taskRoleStatus": {
|
||||
"taskRoleName": "worker",
|
||||
"taskRoleRolloutStatus": {
|
||||
"overallRolloutServiceVersion": null,
|
||||
"overallRolloutStatus": "UNKNOWN",
|
||||
"overallRolloutStartTimestamp": null,
|
||||
"overallRolloutEndTimestamp": null,
|
||||
"currentRolloutScaleUnit": null,
|
||||
"currentRolloutTaskIndexes": null,
|
||||
"currentRolloutStatus": "UNKNOWN",
|
||||
"currentRolloutStartTimestamp": null,
|
||||
"currentRolloutEndTimestamp": null
|
||||
},
|
||||
"frameworkVersion": 10
|
||||
},
|
||||
"taskStatuses": {
|
||||
"taskRoleName": "worker",
|
||||
"taskStatusArray": [
|
||||
{
|
||||
"taskIndex": 0,
|
||||
"taskRoleName": "worker",
|
||||
"taskState": "CONTAINER_RUNNING",
|
||||
"taskRetryPolicyState": {
|
||||
"retriedCount": 0,
|
||||
"succeededRetriedCount": 0,
|
||||
"transientNormalRetriedCount": 0,
|
||||
"transientConflictRetriedCount": 0,
|
||||
"nonTransientRetriedCount": 0,
|
||||
"unKnownRetriedCount": 0
|
||||
},
|
||||
"taskCreatedTimestamp": 1565337479036,
|
||||
"taskCompletedTimestamp": null,
|
||||
"taskServiceStatus": {
|
||||
"serviceVersion": 0
|
||||
},
|
||||
"containerId": "container_e34_1565337391589_0002_01_000002",
|
||||
"containerHost": "0.0.0.38",
|
||||
"containerIp": "0.0.0.38",
|
||||
"containerPorts": "ssh:34235;http:34236;model_server:34237;",
|
||||
"containerGpus": 8,
|
||||
"containerLogHttpAddress": "http://0.0.0.38:8042/node/containerlogs/container_e34_1565337391589_0002_01_000002/core/",
|
||||
"containerConnectionLostCount": 0,
|
||||
"containerIsDecommissioning": null,
|
||||
"containerLaunchedTimestamp": 1565337482022,
|
||||
"containerCompletedTimestamp": null,
|
||||
"containerExitCode": null,
|
||||
"containerExitDescription": null,
|
||||
"containerExitDiagnostics": null,
|
||||
"containerExitType": null
|
||||
}
|
||||
],
|
||||
"frameworkVersion": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { IJobInfo } from '../../../src/models/job';
|
||||
|
||||
export const testJobList: IJobInfo[] = [{
|
||||
"appExitCode": 0,
|
||||
"completedTime": 1563499887777,
|
||||
"createdTime": 1563499625106,
|
||||
"executionType": "STOP",
|
||||
"name": "sklearn-mnist",
|
||||
"retries": 0,
|
||||
"retryDetails": {
|
||||
"platform": 0,
|
||||
"resource": 0,
|
||||
"user": 0
|
||||
},
|
||||
"state": "SUCCEEDED",
|
||||
"subState": "FRAMEWORK_COMPLETED",
|
||||
"totalGpuNumber": 0,
|
||||
"totalTaskNumber": 1,
|
||||
"totalTaskRoleNumber": 1,
|
||||
"username": "test",
|
||||
"virtualCluster": "default"
|
||||
}];
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { IJobSshInfo } from '../../../src/models/job';
|
||||
|
||||
export const testJobSshInfo: IJobSshInfo = {
|
||||
"containers": [
|
||||
{
|
||||
"id": "container_e34_1565337391589_0002_01_000002",
|
||||
"sshIp": "0.0.0.38",
|
||||
"sshPort": "34235"
|
||||
}
|
||||
],
|
||||
"keyPair": {
|
||||
"folderPath": "hdfs://0.0.0.34:9000/Container/core/core~tensorflow_serving_mnist_2019_6585ba19/ssh/keyFiles",
|
||||
"publicKeyFileName": "core~tensorflow_serving_mnist_2019_6585ba19.pub",
|
||||
"privateKeyFileName": "core~tensorflow_serving_mnist_2019_6585ba19",
|
||||
"privateKeyDirectDownloadLink": "http://0.0.0.34/a/0.0.0.34:5070/webhdfs/v1/Container/core/core~tensorflow_serving_mnist_2019_6585ba19/ssh/keyFiles/core~tensorflow_serving_mnist_2019_6585ba19?op=OPEN"
|
||||
}
|
||||
};
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { IJobStatus } from '../../../src/models/job';
|
||||
|
||||
export const testJobStatus: IJobStatus = {
|
||||
"name": "tensorflow_serving_mnist_2019_6585ba19",
|
||||
"jobStatus": {
|
||||
"username": "core",
|
||||
"state": "RUNNING",
|
||||
"subState": "APPLICATION_RUNNING",
|
||||
"executionType": "START",
|
||||
"retries": 1,
|
||||
"retryDetails": {
|
||||
"user": 0,
|
||||
"platform": 1,
|
||||
"resource": 0
|
||||
},
|
||||
"createdTime": 1565329763372,
|
||||
"completedTime": null,
|
||||
"appId": "application_1565337391589_0002",
|
||||
"appProgress": 0,
|
||||
"appTrackingUrl": "http://0.0.0.34/yarn/0.0.0.34:8088/proxy/application_1565337391589_0002/",
|
||||
"appLaunchedTime": 1565337476313,
|
||||
"appCompletedTime": null,
|
||||
"appExitCode": null,
|
||||
"appExitSpec": null,
|
||||
"appExitDiagnostics": null,
|
||||
"appExitMessages": {
|
||||
"container": null,
|
||||
"runtime": null,
|
||||
"launcher": null
|
||||
},
|
||||
"appExitTriggerMessage": null,
|
||||
"appExitTriggerTaskRoleName": null,
|
||||
"appExitTriggerTaskIndex": null,
|
||||
"appExitType": null,
|
||||
"virtualCluster": "default"
|
||||
},
|
||||
"taskRoles": {
|
||||
"worker": {
|
||||
"taskRoleStatus": {
|
||||
"name": "worker"
|
||||
},
|
||||
"taskStatuses": [
|
||||
{
|
||||
"taskIndex": 0,
|
||||
"taskState": "RUNNING",
|
||||
"containerId": "container_e34_1565337391589_0002_01_000002",
|
||||
"containerIp": "0.0.0.38",
|
||||
"containerPorts": {
|
||||
"ssh": "34235",
|
||||
"http": "34236",
|
||||
"model_server": "34237"
|
||||
},
|
||||
"containerGpus": 8,
|
||||
"containerLog": "http://0.0.0.34/yarn/0.0.0.38:8042/node/containerlogs/container_e34_1565337391589_0002_01_000002/core/",
|
||||
"containerExitCode": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { INodeResource } from '../../../src/models/virtualCluster';
|
||||
|
||||
export const testNodeResources: { [id: string]: INodeResource } = {
|
||||
"0.0.0.35": {
|
||||
"gpuTotal": 1,
|
||||
"gpuUsed": 1,
|
||||
"gpuAvaiable": 0
|
||||
},
|
||||
"0.0.0.26": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.39": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.30": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.42": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.27": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.36": {
|
||||
"gpuTotal": 1,
|
||||
"gpuUsed": 1,
|
||||
"gpuAvaiable": 0
|
||||
},
|
||||
"0.0.0.28": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.33": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.24": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.29": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.37": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.41": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.32": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.31": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
},
|
||||
"0.0.0.38": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 1,
|
||||
"gpuAvaiable": 3
|
||||
},
|
||||
"0.0.0.40": {
|
||||
"gpuTotal": 4,
|
||||
"gpuUsed": 0,
|
||||
"gpuAvaiable": 4
|
||||
}
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { IUserInfo } from '../../../src/models/user';
|
||||
|
||||
export const testUserInfo: IUserInfo = {
|
||||
"username": "core",
|
||||
"grouplist": [
|
||||
"adminGroup",
|
||||
"default",
|
||||
"admingroup"
|
||||
],
|
||||
"email": "",
|
||||
"extension": {
|
||||
"virtualCluster": [
|
||||
"default"
|
||||
]
|
||||
},
|
||||
"admin": true,
|
||||
"virtualCluster": [
|
||||
"default"
|
||||
]
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import { IVirtualCluster } from '../../../src/models/virtualCluster';
|
||||
|
||||
export const testVirtualClusters: IVirtualCluster = {
|
||||
"capacity": 26.481485,
|
||||
"maxCapacity": 100,
|
||||
"usedCapacity": 5.555556,
|
||||
"numActiveJobs": 3,
|
||||
"numJobs": 3,
|
||||
"numPendingJobs": 0,
|
||||
"resourcesUsed": {
|
||||
"memory": 27648,
|
||||
"vCores": 15,
|
||||
"GPUs": 3
|
||||
},
|
||||
"status": "RUNNING",
|
||||
"dedicated": false,
|
||||
"resourcesTotal": {
|
||||
"vCores": 85.8000114,
|
||||
"memory": 740295.209472,
|
||||
"GPUs": 14.3000019
|
||||
},
|
||||
"nodeList": [
|
||||
"0.0.0.35",
|
||||
"0.0.0.26",
|
||||
"0.0.0.39",
|
||||
"0.0.0.42",
|
||||
"0.0.0.27",
|
||||
"0.0.0.36",
|
||||
"0.0.0.28",
|
||||
"0.0.0.33",
|
||||
"0.0.0.24",
|
||||
"0.0.0.29",
|
||||
"0.0.0.37",
|
||||
"0.0.0.41",
|
||||
"0.0.0.32",
|
||||
"0.0.0.38",
|
||||
"0.0.0.40"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as chai from 'chai';
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
import * as nock from 'nock';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { AuthnClient } from '../../src/client/authnClient';
|
||||
import { IAuthnInfo } from '../../src/models/authn';
|
||||
import { IPAICluster } from '../../src/models/cluster';
|
||||
|
||||
const testUri = 'openpai-js-sdk.test/rest-server';
|
||||
|
||||
const cluster: IPAICluster = {
|
||||
password: 'test',
|
||||
rest_server_uri: testUri,
|
||||
username: 'test'
|
||||
};
|
||||
const authnClient = new AuthnClient(cluster);
|
||||
|
||||
chai.use(dirtyChai);
|
||||
nock(`http://${testUri}`).post(`/api/v1/token`).reply(200, { token: 'token' });
|
||||
nock(`http://${testUri}`).post(`/api/v1/authn/basic/login`).reply(200, { token: 'token' });
|
||||
|
||||
describe('Get authn infomation', () => {
|
||||
const response: IAuthnInfo = {
|
||||
'authn_type': 'basic',
|
||||
'loginURI': '/api/v1/authn/basic/login',
|
||||
'loginURIMethod': 'post'
|
||||
};
|
||||
nock(`http://${testUri}`).get(`/api/v1/authn/info`).reply(200, response);
|
||||
|
||||
it('should return the user info', async () => {
|
||||
const result = await authnClient.info();
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Basic login', () => {
|
||||
const response = {
|
||||
token: 'token'
|
||||
};
|
||||
|
||||
it('should return the login info', async () => {
|
||||
const result = await authnClient.login();
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('OIDC login', () => {
|
||||
it('should return something', async () => {
|
||||
nock(`http://${testUri}`).get(`/api/v1/authn/oidc/login`).reply(200, 'test');
|
||||
const result = await authnClient.oidcLogin();
|
||||
|
||||
expect(result).to.be.a('string');
|
||||
})
|
||||
});
|
||||
|
||||
describe('OIDC logout', () => {
|
||||
it('should return something', async () => {
|
||||
nock(`http://${testUri}`).get(`/api/v1/authn/oidc/logout`).reply(200, 'test');
|
||||
const result = await authnClient.oidcLogout();
|
||||
|
||||
expect(result).to.be.a('string');
|
||||
})
|
||||
});
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as chai from 'chai';
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
import * as nock from 'nock';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { OpenPAIBaseClient } from '../../src/client/baseClient';
|
||||
import { IPAICluster } from '../../src/models/cluster';
|
||||
|
||||
const testUri = 'openpai-js-sdk.test/rest-server';
|
||||
|
||||
const cluster: IPAICluster = {
|
||||
password: 'test',
|
||||
rest_server_uri: testUri,
|
||||
username: 'test'
|
||||
};
|
||||
const baseClient = new OpenPAIBaseClient(cluster);
|
||||
|
||||
chai.use(dirtyChai);
|
||||
|
||||
describe('Get token', () => {
|
||||
const response = {
|
||||
token: 'eyJhb...'
|
||||
};
|
||||
nock(`http://${testUri}`).post(`/api/v1/token`).reply(200, response);
|
||||
|
||||
it('should return a token', async () => {
|
||||
const result = await baseClient.token();
|
||||
expect(result).to.be.a('string');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get cluster info', () => {
|
||||
const response = {
|
||||
authnMethod: "basic",
|
||||
launcherType: "yarn",
|
||||
name: "PAI RESTful API",
|
||||
version: "v0.14.0"
|
||||
};
|
||||
nock(`http://${testUri}`).get(`/api/v1/`).reply(200, response);
|
||||
|
||||
it('should return the cluster info', async () => {
|
||||
const result = await baseClient.getClusterInfo();
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as chai from 'chai';
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
import * as nock from 'nock';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { JobClient } from '../../src/client/jobClient';
|
||||
import { IPAICluster } from '../../src/models/cluster';
|
||||
import { testJobConfig, testJobConfigV1 } from '../common/test_data/testJobConfig';
|
||||
import { testJobFrameworkInfo } from '../common/test_data/testJobFrameworkInfo';
|
||||
import { testJobList } from '../common/test_data/testJobList';
|
||||
import { testJobSshInfo } from '../common/test_data/testJobSshInfo';
|
||||
import { testJobStatus } from '../common/test_data/testJobStatus';
|
||||
|
||||
const testUri = 'openpai-js-sdk.test/rest-server';
|
||||
|
||||
const cluster: IPAICluster = {
|
||||
password: 'test',
|
||||
rest_server_uri: testUri,
|
||||
username: 'test'
|
||||
};
|
||||
const jobClient = new JobClient(cluster);
|
||||
|
||||
chai.use(dirtyChai);
|
||||
|
||||
describe('List jobs', () => {
|
||||
const response = testJobList;
|
||||
nock(`http://${testUri}`).get(`/api/v1/jobs`).reply(200, response);
|
||||
|
||||
it('should return a list of jobs', async () => {
|
||||
const result = await jobClient.list();
|
||||
expect(result).is.not.empty();
|
||||
}).timeout(10000);
|
||||
});
|
||||
|
||||
describe('List jobs with query', () => {
|
||||
const response = testJobList;
|
||||
const queryString = 'username=core';
|
||||
nock(`http://${testUri}`).get(`/api/v1/jobs?${queryString}`).reply(200, response);
|
||||
|
||||
it('should return a list of jobs', async () => {
|
||||
const result = await jobClient.list(queryString);
|
||||
expect(result).is.not.empty();
|
||||
}).timeout(10000);
|
||||
});
|
||||
|
||||
describe('Get job status', () => {
|
||||
const response = testJobStatus;
|
||||
const userName = 'core';
|
||||
const jobName = 'tensorflow_serving_mnist_2019_6585ba19';
|
||||
nock(`http://${testUri}`).get(`/api/v2/user/${userName}/jobs/${jobName}`).reply(200, response);
|
||||
|
||||
it('should return the job status', async () => {
|
||||
const result = await jobClient.get(userName, jobName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
})
|
||||
|
||||
describe('Get job framework information', () => {
|
||||
const response = testJobFrameworkInfo;
|
||||
const userName = 'core';
|
||||
const jobName = 'tensorflow_serving_mnist_2019_6585ba19';
|
||||
nock(`http://${testUri}`).get(`/api/v2/jobs/${userName}~${jobName}`).reply(200, response);
|
||||
|
||||
|
||||
it('should return the job framework info', async () => {
|
||||
const result = await jobClient.getFrameworkInfo(userName, jobName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
})
|
||||
|
||||
describe('Get job config', () => {
|
||||
const response = testJobConfig;
|
||||
const userName = 'core';
|
||||
const jobName = 'tensorflow_serving_mnist_2019_6585ba19';
|
||||
nock(`http://${testUri}`).get(`/api/v2/jobs/${userName}~${jobName}/config`).reply(200, response);
|
||||
|
||||
it('should return a job config', async() => {
|
||||
const result = await jobClient.getConfig(userName, jobName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Submit a job', () => {
|
||||
const jobConfig = testJobConfig;
|
||||
const response = {
|
||||
token: 'eyJhb...'
|
||||
};
|
||||
nock(`http://${testUri}`).post(`/api/v1/token`).reply(200, response);
|
||||
nock(`http://${testUri}`).post(`/api/v2/jobs`).reply(202);
|
||||
|
||||
it('should submit a job without exception', async() => {
|
||||
await jobClient.submit(jobConfig);
|
||||
})
|
||||
});
|
||||
|
||||
describe('Submit a v1 job', () => {
|
||||
const jobConfigV1 = testJobConfigV1;
|
||||
const response = {
|
||||
token: 'eyJhb...'
|
||||
};
|
||||
const userName = 'core';
|
||||
nock(`http://${testUri}`).post(`/api/v1/token`).reply(200, response);
|
||||
nock(`http://${testUri}`).post(`/api/v1/user/${userName}/jobs`).reply(202);
|
||||
|
||||
it('should submit the job without exception', async() => {
|
||||
await jobClient.submitV1(userName, jobConfigV1);
|
||||
})
|
||||
});
|
||||
|
||||
describe('Get job ssh information with user name and job name', () => {
|
||||
const response = testJobSshInfo;
|
||||
const userName = 'core';
|
||||
const jobName = 'tensorflow_serving_mnist_2019_6585ba19';
|
||||
nock(`http://${testUri}`).get(`/api/v1/user/${userName}/jobs/${jobName}/ssh`).reply(200, response);
|
||||
|
||||
it('should return the job ssh info', async() => {
|
||||
const result = await jobClient.getSshInfo(userName, jobName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get job ssh information with job name', () => {
|
||||
const response = testJobSshInfo;
|
||||
const jobName = 'tensorflow_serving_mnist_2019_6585ba19';
|
||||
nock(`http://${testUri}`).get(`/api/v1/jobs/${jobName}/ssh`).reply(200, response);
|
||||
|
||||
it('should return the job ssh info', async() => {
|
||||
const result = await jobClient.getSshInfo(jobName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Start a job', () => {
|
||||
const response = {
|
||||
"message": "execute job tensorflow_serving_mnist_2019_6585ba19 successfully"
|
||||
};
|
||||
const userName = 'core';
|
||||
const jobName = 'tensorflow_serving_mnist_2019_6585ba19';
|
||||
nock(`http://${testUri}`).put(`/api/v2/user/${userName}/jobs/${jobName}/executionType`).reply(200, response);
|
||||
|
||||
it('should start the job', async() => {
|
||||
const result = await jobClient.execute(userName, jobName, 'START');
|
||||
expect(result).to.be.eql(response);
|
||||
})
|
||||
});
|
||||
|
||||
describe('Stop a job', () => {
|
||||
const response = {
|
||||
"message": "execute job tensorflow_serving_mnist_2019_6585ba19 successfully"
|
||||
};
|
||||
const userName = 'core';
|
||||
const jobName = 'tensorflow_serving_mnist_2019_6585ba19';
|
||||
nock(`http://${testUri}`).put(`/api/v2/user/${userName}/jobs/${jobName}/executionType`).reply(200, response);
|
||||
|
||||
it('should stop the job', async() => {
|
||||
const result = await jobClient.execute(userName, jobName, 'STOP');
|
||||
expect(result).to.be.eql(response);
|
||||
})
|
||||
});
|
||||
|
||||
describe('Delete a job', () => {
|
||||
const response = {
|
||||
"message": "deleted job tensorflow_serving_mnist_2019_6585ba19_test successfully"
|
||||
};
|
||||
const userName = 'core';
|
||||
const jobName = 'tensorflow_serving_mnist_2019_6585ba19_test';
|
||||
nock(`http://${testUri}`).delete(`/api/v2/user/${userName}/jobs/${jobName}`).reply(201, response);
|
||||
|
||||
it('should delete the job', async() => {
|
||||
const result = await jobClient.delete(userName, jobName);
|
||||
expect(result).to.be.eql(response);
|
||||
})
|
||||
});
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as chai from 'chai';
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
import * as nock from 'nock';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { StorageClient } from '../../src/client/storageClient';
|
||||
import { IPAICluster } from '../../src/models/cluster';
|
||||
import { IStorageConfig, IStorageServer } from '../../src/models/storage';
|
||||
|
||||
const testUri = 'openpai-js-sdk.test/rest-server';
|
||||
|
||||
const cluster: IPAICluster = {
|
||||
https: true,
|
||||
rest_server_uri: testUri,
|
||||
token: 'token',
|
||||
};
|
||||
const storageClient = new StorageClient(cluster);
|
||||
|
||||
chai.use(dirtyChai);
|
||||
nock(`http://${testUri}`).post(`/api/v1/authn/basic/login`).reply(200, { token: 'token' });
|
||||
|
||||
describe('Get storage infomation by storage name', () => {
|
||||
const response: IStorageServer = {
|
||||
'data': {
|
||||
'test': 'test'
|
||||
},
|
||||
'extension': {},
|
||||
'spn': 'test',
|
||||
'type': 'azureblob'
|
||||
};
|
||||
const testName = 'testStorage';
|
||||
nock(`https://${testUri}`).get(`/api/v2/storage/server/${testName}`).reply(200, response);
|
||||
|
||||
it('should return the storage info', async () => {
|
||||
const result = await storageClient.getServerByName(testName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get storage information list', () => {
|
||||
const response: IStorageServer[] = [{
|
||||
'data': {
|
||||
'test': 'test'
|
||||
},
|
||||
'extension': {},
|
||||
'spn': 'test',
|
||||
'type': 'azureblob'
|
||||
}];
|
||||
nock(`https://${testUri}`).get(`/api/v2/storage/server`).reply(200, response);
|
||||
|
||||
it('should return the storage info', async () => {
|
||||
const result = await storageClient.getServer();
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get storage config by storage name', () => {
|
||||
const response: IStorageConfig = {
|
||||
"name": "PAI_SHARE",
|
||||
"default": true,
|
||||
"servers": [
|
||||
"PAI_SHARE_SERVER"
|
||||
],
|
||||
"mountInfos": [
|
||||
{
|
||||
"mountPoint": "/data",
|
||||
"path": "data",
|
||||
"server": "PAI_SHARE_SERVER",
|
||||
"permission": "rw"
|
||||
},
|
||||
{
|
||||
"mountPoint": "/home",
|
||||
"path": "users/${PAI_USER_NAME}",
|
||||
"server": "PAI_SHARE_SERVER",
|
||||
"permission": "rw"
|
||||
}
|
||||
]
|
||||
}
|
||||
const testName = 'testStorage';
|
||||
nock(`https://${testUri}`).get(`/api/v2/storage/config/${testName}`).reply(200, response);
|
||||
|
||||
it('should return the storage info', async () => {
|
||||
const result = await storageClient.getConfigByName(testName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get storage config list', () => {
|
||||
const response: IStorageConfig[] = [
|
||||
{
|
||||
"name": "PAI_SHARE",
|
||||
"default": true,
|
||||
"servers": [
|
||||
"PAI_SHARE_SERVER"
|
||||
],
|
||||
"mountInfos": [
|
||||
{
|
||||
"mountPoint": "/data",
|
||||
"path": "data",
|
||||
"server": "PAI_SHARE_SERVER",
|
||||
"permission": "rw"
|
||||
},
|
||||
{
|
||||
"mountPoint": "/home",
|
||||
"path": "users/${PAI_USER_NAME}",
|
||||
"server": "PAI_SHARE_SERVER",
|
||||
"permission": "rw"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
nock(`https://${testUri}`).get(`/api/v2/storage/config`).reply(200, response);
|
||||
|
||||
it('should return the storage info', async () => {
|
||||
const result = await storageClient.getConfig();
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,174 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as chai from 'chai';
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
import * as nock from 'nock';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { UserClient } from '../../src/client/userClient';
|
||||
import { IPAICluster } from '../../src/models/cluster';
|
||||
import { testAllUsers } from '../common/test_data/testAllUsers';
|
||||
import { testUserInfo } from '../common/test_data/testUserInfo';
|
||||
|
||||
const testUri = 'openpai-js-sdk.test/rest-server';
|
||||
|
||||
const cluster: IPAICluster = {
|
||||
password: 'test',
|
||||
rest_server_uri: testUri,
|
||||
username: 'test'
|
||||
};
|
||||
const userClient = new UserClient(cluster);
|
||||
|
||||
chai.use(dirtyChai);
|
||||
nock(`http://${testUri}`).post(`/api/v1/authn/basic/login`).reply(200, { token: 'token' });
|
||||
|
||||
describe('Get user infomation', () => {
|
||||
const response = testUserInfo;
|
||||
const userName = 'core';
|
||||
nock(`http://${testUri}`).get(`/api/v2/user/${userName}`).reply(200, response);
|
||||
nock(`http://${testUri}`).post(`/api/v1/authn/basic/login`).reply(200, { token: 'token' });
|
||||
|
||||
it('should return the user info', async () => {
|
||||
const result = await userClient.get(userName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('List all users', () => {
|
||||
const response = testAllUsers;
|
||||
nock(`http://${testUri}`).get(`/api/v2/user/`).reply(200, response);
|
||||
|
||||
it('should return all users', async () => {
|
||||
const result = await userClient.list();
|
||||
expect(result).is.not.empty();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Create a new user', () => {
|
||||
const response = { "message": "User is created successfully" };
|
||||
nock(`http://${testUri}`).post(`/api/v2/user/`).reply(201, response);
|
||||
|
||||
it('should create a new user', async () => {
|
||||
const result = await userClient.create('core11', '11111111', false, '', ['default']);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update user extension data', () => {
|
||||
const response = { "message": "Update user extension data successfully." };
|
||||
const userName = 'core11';
|
||||
nock(`http://${testUri}`).put(`/api/v2/user/${userName}/extension`).reply(201, response);
|
||||
|
||||
it('should update successfully', async () => {
|
||||
const result = await userClient.updateExtension(userName, {'ex1': 'ex2'});
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Delete a user', () => {
|
||||
const response = { "message": "user is removed successfully" };
|
||||
const userName = 'core11';
|
||||
nock(`http://${testUri}`).delete(`/api/v2/user/${userName}`).reply(200, response);
|
||||
|
||||
it('should delete successfully', async () => {
|
||||
const result = await userClient.delete(userName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update user virtualCluster data', () => {
|
||||
const response = { "message": "Update user virtualCluster data successfully." };
|
||||
const userName = 'core11';
|
||||
nock(`http://${testUri}`).put(`/api/v2/user/${userName}/virtualcluster`).reply(201, response);
|
||||
|
||||
it('should update successfully', async () => {
|
||||
const result = await userClient.updateVirtualcluster(userName, ['default']);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update user password', () => {
|
||||
const response = { "message": "update user password successfully." };
|
||||
const userName = 'core11';
|
||||
const newPassword = 'newPassword';
|
||||
nock(`http://${testUri}`).put(`/api/v2/user/${userName}/password`).reply(201, response);
|
||||
|
||||
it('should update successfully', async () => {
|
||||
const result = await userClient.updatePassword(userName, undefined, newPassword);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
describe('Update user email', () => {
|
||||
const response = { "message": "Update user email data successfully." };
|
||||
const userName = 'core11';
|
||||
const newEmail = 'new@email.test';
|
||||
nock(`http://${testUri}`).put(`/api/v2/user/${userName}/email`).reply(201, response);
|
||||
|
||||
it('should update successfully', async () => {
|
||||
const result = await userClient.updateEmail(userName, newEmail);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update user admin permission', () => {
|
||||
const response = { "message": "Update user admin permission successfully." };
|
||||
const userName = 'core11';
|
||||
const newAdminPermission = false;
|
||||
nock(`http://${testUri}`).put(`/api/v2/user/${userName}/admin`).reply(201, response);
|
||||
|
||||
it('should update successfully', async () => {
|
||||
const result = await userClient.updateAdminPermission(userName, newAdminPermission);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update user group list', () => {
|
||||
const userName = 'core11';
|
||||
const newGroupList = ['newGroup1', 'newGroup2'];
|
||||
const response = { "message": "update user grouplist successfully." };
|
||||
nock(`http://${testUri}`).put(`/api/v2/user/${userName}/grouplist`).reply(201, response);
|
||||
|
||||
it('should update successfully', async () => {
|
||||
const result = await userClient.updateGroupList(userName, newGroupList);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Add new group into user group list', () => {
|
||||
const userName = 'core11';
|
||||
const groupName = 'testGroup';
|
||||
const response = { "message": `User ${userName} is added into group ${groupName}` };
|
||||
nock(`http://${testUri}`).put(`/api/v2/user/${userName}/group`).reply(201, response);
|
||||
|
||||
it('should add successfully', async () => {
|
||||
const result = await userClient.addGroup(userName, groupName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Remove group from user group list', () => {
|
||||
const userName = 'core11';
|
||||
const groupName = 'testGroup';
|
||||
const response = { "message": `User ${userName} is removed from group ${groupName}` };
|
||||
nock(`http://${testUri}`).delete(`/api/v2/user/${userName}/group`).reply(201, response);
|
||||
|
||||
it('should remove successfully', async () => {
|
||||
const result = await userClient.removeGroup(userName, groupName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as chai from 'chai';
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
import * as nock from 'nock';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { VirtualClusterClient } from '../../src/client/virtualClusterClient';
|
||||
import { IPAICluster } from '../../src/models/cluster';
|
||||
import { testAllVirtualClusters } from '../common/test_data/testAllVirtualClusters';
|
||||
import { testNodeResources } from '../common/test_data/testNodeResources';
|
||||
import { testVirtualClusters } from '../common/test_data/testVirtualCluster';
|
||||
|
||||
const testUri = 'openpai-js-sdk.test/rest-server';
|
||||
|
||||
const cluster: IPAICluster = {
|
||||
password: 'test',
|
||||
rest_server_uri: testUri,
|
||||
username: 'test'
|
||||
};
|
||||
const virtualClusterClient = new VirtualClusterClient(cluster);
|
||||
|
||||
chai.use(dirtyChai);
|
||||
nock(`http://${testUri}`).post(`/api/v1/authn/basic/login`).reply(200, { token: 'token' });
|
||||
|
||||
describe('List all virtual clusters', () => {
|
||||
const response = testAllVirtualClusters;
|
||||
nock(`http://${testUri}`).get(`/api/v2/virtual-clusters`).reply(200, response);
|
||||
nock(`http://${testUri}`).post(`/api/v1/authn/basic/login`).reply(200, { token: 'token' });
|
||||
|
||||
it('should return all virtual clusters', async () => {
|
||||
const result = await virtualClusterClient.list();
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get a virtual cluster', () => {
|
||||
const response = testVirtualClusters;
|
||||
const vcName = 'default';
|
||||
nock(`http://${testUri}`).get(`/api/v2/virtual-clusters/${vcName}`).reply(200, response);
|
||||
|
||||
it('should return the virtual cluster info', async () => {
|
||||
const result = await virtualClusterClient.get(vcName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get virtual cluster node resources', () => {
|
||||
const response = testNodeResources;
|
||||
nock(`http://${testUri}`).get(`/api/v2/virtual-clusters/nodeResource`).reply(200, response);
|
||||
|
||||
it('should return the virtual cluster info', async () => {
|
||||
const result = await virtualClusterClient.getNodeResource();
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Create a new virtual cluster', () => {
|
||||
const vcName = 'testNewVc1';
|
||||
const vcCapacity = 1;
|
||||
const response = { "message": `create vc: ${vcName} to capacity: ${vcCapacity} successfully.` };
|
||||
nock(`http://${testUri}`).put(`/api/v1/virtual-clusters/${vcName}`).reply(201, response);
|
||||
|
||||
it('should return the virtual cluster info', async () => {
|
||||
const result = await virtualClusterClient.createOrUpdate(vcName, vcCapacity, vcCapacity);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Remove a virtual cluster', () => {
|
||||
const vcName = 'testNewVc1';
|
||||
const response = { "message": `Remove vc: ${vcName} successfully` };
|
||||
nock(`http://${testUri}`).delete(`/api/v1/virtual-clusters/${vcName}`).reply(201, response);
|
||||
|
||||
it('should remove successfully', async () => {
|
||||
const result = await virtualClusterClient.delete(vcName);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Change virtual cluster status', () => {
|
||||
const vcName = 'testNewVc1';
|
||||
const vcStatus = 'stopped';
|
||||
const response = { "message": `stop vc ${vcName} successfully` };
|
||||
nock(`http://${testUri}`).put(`/api/v1/virtual-clusters/${vcName}/status`).reply(201, response);
|
||||
|
||||
it('should remove successfully', async () => {
|
||||
const result = await virtualClusterClient.changeStatus(vcName, vcStatus);
|
||||
expect(result).to.be.eql(response);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2019",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"lib": [
|
||||
"es2019"
|
||||
]
|
||||
},
|
||||
"include": ["src", "tests/unit_tests/global.d.ts"],
|
||||
"exclude": ["node_modules", "tests", "out"]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": ["tslint:recommended", "tslint-config-prettier"],
|
||||
"rules": {
|
||||
"object-literal-sort-keys": false
|
||||
},
|
||||
"jsRules": true
|
||||
}
|
Загрузка…
Ссылка в новой задаче