Refine rest API request and error handle (#22)
* split v1 and v2 * add constants and errors * refine and fix tests * fix * add pai errors * update lib * for a clear api folder structure (#24) * set linebreak-style to false * explicit query parameters in get methods (#25) * Yiyi/update clients (#26) * update * update * update vc client * reset Co-authored-by: yiyione <yiyi_one@foxmail.com> * add group client (#27) Co-authored-by: yiyione <yiyi_one@foxmail.com> * change all client method names (#28) Co-authored-by: yiyione <yiyi_one@foxmail.com> * change method names and fix tests (#29) * change all client method names * fix tests Co-authored-by: yiyione <yiyi_one@foxmail.com> Co-authored-by: yiyione <yiyi_one@foxmail.com> Co-authored-by: Yuqing Yang <yuqyang@microsoft.com> Co-authored-by: Yi Yi <yiyi@microsoft.com>
This commit is contained in:
Родитель
12954bd562
Коммит
777ce897a2
|
@ -1,2 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
export {};
|
18
lib/cli.js
18
lib/cli.js
|
@ -1,18 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const commands_1 = require("./commands");
|
||||
/**
|
||||
* the main entry point of the command line tool `pai`
|
||||
*/
|
||||
(async () => {
|
||||
// Util.debugMode = true;
|
||||
const cli = new commands_1.CliEngine();
|
||||
commands_1.registerBuiltinCommands(cli);
|
||||
await cli.load();
|
||||
const result = await cli.evaluate();
|
||||
cli.toScreen(result);
|
||||
await cli.store();
|
||||
})().catch(err => console.error(err));
|
|
@ -1,34 +0,0 @@
|
|||
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>;
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
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;
|
|
@ -1,43 +0,0 @@
|
|||
import { PagedAsyncIterableIterator } from '@azure/core-paging';
|
||||
import { BlobItem, BlobPrefix, ContainerListBlobHierarchySegmentResponse } from '@azure/storage-blob';
|
||||
import { IStorageDetail } from '../models/storage';
|
||||
import { IFileInfo, IStorageNodeClient } from '../models/storageOperation';
|
||||
export declare type BlobIter = PagedAsyncIterableIterator<({
|
||||
kind: 'prefix';
|
||||
} & BlobPrefix) | ({
|
||||
kind: 'blob';
|
||||
} & BlobItem), ContainerListBlobHierarchySegmentResponse>;
|
||||
export declare type BlobEntity = {
|
||||
done?: boolean | undefined;
|
||||
value: ({
|
||||
kind: 'prefix';
|
||||
} & BlobPrefix) | ({
|
||||
kind: 'blob';
|
||||
} & BlobItem);
|
||||
};
|
||||
export declare type BlobValue = ({
|
||||
kind: 'prefix';
|
||||
} & BlobPrefix) | ({
|
||||
kind: 'blob';
|
||||
} & BlobItem);
|
||||
/**
|
||||
* Azure Blob Storage Client.
|
||||
*/
|
||||
export declare class AzureBlobClient implements IStorageNodeClient {
|
||||
mkdirAllowRecursive: boolean;
|
||||
config: IStorageDetail;
|
||||
private client;
|
||||
constructor(config: IStorageDetail);
|
||||
/**
|
||||
* Get status of a path.
|
||||
* @param path The path.
|
||||
*/
|
||||
getinfo(path: string): Promise<IFileInfo>;
|
||||
listdir(path: string): Promise<string[]>;
|
||||
makedir(path: string, mode?: string | undefined): Promise<void>;
|
||||
upload(localPath: string, remotePath: string, opts?: {} | undefined): Promise<void>;
|
||||
download(remotePath: string, localPath: string, opts?: {} | undefined): Promise<void>;
|
||||
delete(path: string): Promise<void>;
|
||||
deleteFolder(path: string): Promise<void>;
|
||||
private deleteBlobsByHierarchy;
|
||||
}
|
|
@ -1,196 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const storage_blob_1 = require("@azure/storage-blob");
|
||||
const Path = require("path");
|
||||
/**
|
||||
* Azure Blob Storage Client.
|
||||
*/
|
||||
class AzureBlobClient {
|
||||
constructor(config) {
|
||||
this.mkdirAllowRecursive = true;
|
||||
this.config = config;
|
||||
const data = config.data;
|
||||
if (config.type !== 'azureBlob' ||
|
||||
!data ||
|
||||
!data.containerName ||
|
||||
!(data.accountKey || data.accountSASToken)) {
|
||||
throw new Error(`WrongStorageDetail: ${JSON.stringify(config)}`);
|
||||
}
|
||||
if (data.accountKey) { // use the accountKey
|
||||
const credential = new storage_blob_1.StorageSharedKeyCredential(data.accountName, data.accountKey);
|
||||
const blobClient = new storage_blob_1.BlobServiceClient(`https://${data.accountName}.blob.core.windows.net`, credential);
|
||||
this.client = blobClient.getContainerClient(data.containerName);
|
||||
}
|
||||
else { // SAS token
|
||||
let url = data.accountSASToken;
|
||||
if (!url.startsWith('https://')) {
|
||||
url = `https://${data.accountName}.blob.core.windows.net${data.accountSASToken}`;
|
||||
}
|
||||
const blobClient = new storage_blob_1.BlobServiceClient(url);
|
||||
this.client = blobClient.getContainerClient(data.containerName);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get status of a path.
|
||||
* @param path The path.
|
||||
*/
|
||||
async getinfo(path) {
|
||||
const blobClient = this.client.getBlockBlobClient(path);
|
||||
try {
|
||||
const properties = await blobClient.getProperties();
|
||||
if (!properties.metadata || !properties.metadata.hdi_isfolder) {
|
||||
return {
|
||||
size: properties.contentLength,
|
||||
type: 'file',
|
||||
mtime: properties.lastModified
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
type: 'directory',
|
||||
mtime: properties.lastModified
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
if (err.details && err.details.errorCode === 'BlobNotFound') {
|
||||
const iter = await this.client.listBlobsByHierarchy('/', {
|
||||
prefix: path.endsWith('/') ? path : path + '/',
|
||||
includeMetadata: true
|
||||
}).byPage({
|
||||
continuationToken: undefined,
|
||||
maxPageSize: 1
|
||||
}).next();
|
||||
const prefixes = iter.value.segment.blobPrefixes;
|
||||
const blobs = iter.value.segment.blobItems;
|
||||
if ((prefixes && prefixes.length > 0) || blobs.length > 0) {
|
||||
return {
|
||||
type: 'directory'
|
||||
};
|
||||
}
|
||||
}
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async listdir(path) {
|
||||
try {
|
||||
const result = [];
|
||||
const currentPrefixes = new Set();
|
||||
let currentContinuationToken;
|
||||
let iter;
|
||||
do {
|
||||
iter = await this.client.listBlobsByHierarchy('/', {
|
||||
prefix: path.endsWith('/') ? path : path + '/',
|
||||
includeMetadata: true
|
||||
}).byPage({
|
||||
continuationToken: currentContinuationToken,
|
||||
maxPageSize: 20
|
||||
}).next();
|
||||
currentContinuationToken = iter.value.continuationToken;
|
||||
const prefixes = iter.value.segment.blobPrefixes;
|
||||
if (prefixes) {
|
||||
prefixes.forEach(item => {
|
||||
result.push(Path.basename(item.name));
|
||||
currentPrefixes.add(item.name);
|
||||
});
|
||||
}
|
||||
const blobs = iter.value.segment.blobItems;
|
||||
for (const blob of blobs) {
|
||||
if (blob.metadata && blob.metadata.hdi_isfolder && blob.metadata.hdi_isfolder === 'true') {
|
||||
if (currentPrefixes.has(`${blob.name}/`)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
result.push(Path.basename(blob.name));
|
||||
}
|
||||
} while (currentContinuationToken);
|
||||
return result;
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async makedir(path, mode) {
|
||||
try {
|
||||
await this.client.getBlockBlobClient(path).upload('', 0, {
|
||||
metadata: {
|
||||
hdi_isfolder: 'true'
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async upload(localPath, remotePath, opts) {
|
||||
try {
|
||||
const blobClient = this.client.getBlockBlobClient(remotePath);
|
||||
await blobClient.uploadFile(localPath);
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async download(remotePath, localPath, opts) {
|
||||
try {
|
||||
const blobClient = this.client.getBlockBlobClient(remotePath);
|
||||
await blobClient.downloadToFile(localPath);
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async delete(path) {
|
||||
try {
|
||||
const blobClient = this.client.getBlockBlobClient(path);
|
||||
await blobClient.delete();
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async deleteFolder(path) {
|
||||
try {
|
||||
const info = await this.getinfo(path);
|
||||
if (info.type === 'file') {
|
||||
await this.client.deleteBlob(path);
|
||||
}
|
||||
else {
|
||||
await this.deleteBlobsByHierarchy(this.client, path);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async deleteBlobsByHierarchy(client, prefix) {
|
||||
const iter = client.listBlobsByHierarchy('/', {
|
||||
prefix: prefix.endsWith('/') ? prefix : prefix + '/'
|
||||
});
|
||||
let blobItem = await iter.next();
|
||||
while (!blobItem.done) {
|
||||
const blob = blobItem.value;
|
||||
if (blob.kind === 'blob') {
|
||||
await client.deleteBlob(blob.name);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
await client.deleteBlob(blob.name.slice(0, -1));
|
||||
}
|
||||
catch { }
|
||||
await this.deleteBlobsByHierarchy(client, blob.name);
|
||||
}
|
||||
blobItem = await iter.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.AzureBlobClient = AzureBlobClient;
|
|
@ -1,28 +0,0 @@
|
|||
import { ILoginInfo } from '../models/authn';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
/**
|
||||
* OpenPAI basic client.
|
||||
*/
|
||||
export declare class OpenPAIBaseClient {
|
||||
protected static readonly TIMEOUT: number;
|
||||
/**
|
||||
* get cluster configuration / info
|
||||
*/
|
||||
config: any;
|
||||
protected cluster: IPAICluster;
|
||||
private cacheToken?;
|
||||
constructor(cluster: IPAICluster);
|
||||
/**
|
||||
* parse information from pai_uri
|
||||
* refer to tests/unit_tests/baseClient.spec.ts
|
||||
*/
|
||||
static parsePaiUri(cluster: IPAICluster): IPAICluster;
|
||||
/**
|
||||
* Get OpenPAI access token, will call /api/v1/token.
|
||||
*/
|
||||
token(): Promise<string>;
|
||||
/**
|
||||
* Basic login.
|
||||
*/
|
||||
login(): Promise<ILoginInfo>;
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const request = require("request-promise-native");
|
||||
const url_1 = require("url");
|
||||
const util_1 = require("../commom/util");
|
||||
/**
|
||||
* OpenPAI basic client.
|
||||
*/
|
||||
class OpenPAIBaseClient {
|
||||
constructor(cluster) {
|
||||
/**
|
||||
* get cluster configuration / info
|
||||
*/
|
||||
this.config = {
|
||||
/**
|
||||
* username from cluster config
|
||||
*/
|
||||
username: () => {
|
||||
return this.cluster.username;
|
||||
},
|
||||
/**
|
||||
* Get OpenPAI cluster info, will call /api/v1.
|
||||
*/
|
||||
clusterInfo: async () => {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/`);
|
||||
const res = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
};
|
||||
this.cluster = OpenPAIBaseClient.parsePaiUri(cluster);
|
||||
}
|
||||
/**
|
||||
* parse information from pai_uri
|
||||
* refer to tests/unit_tests/baseClient.spec.ts
|
||||
*/
|
||||
static parsePaiUri(cluster) {
|
||||
if (cluster.pai_uri) {
|
||||
const paiUri = new url_1.URL(util_1.Util.fixUrl(cluster.pai_uri));
|
||||
if (!cluster.https) {
|
||||
cluster.https = paiUri.protocol === 'https:';
|
||||
}
|
||||
if (!cluster.rest_server_uri) {
|
||||
cluster.rest_server_uri = paiUri.host + '/rest-server';
|
||||
}
|
||||
if (!cluster.alias) {
|
||||
cluster.alias = paiUri.hostname;
|
||||
}
|
||||
}
|
||||
return 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;
|
||||
}
|
||||
}
|
||||
exports.OpenPAIBaseClient = OpenPAIBaseClient;
|
||||
OpenPAIBaseClient.TIMEOUT = 60 * 1000;
|
|
@ -1,13 +0,0 @@
|
|||
import { IStorageNode, IFileInfo } from '../models/storageOperation';
|
||||
export declare class baseStorageNode implements IStorageNode {
|
||||
getinfo(path: string): Promise<IFileInfo>;
|
||||
listdir(path: string): Promise<string[]>;
|
||||
makedir(path: string, mode?: string | undefined): void;
|
||||
upload(localPath: string, remotePath: string, opts?: {} | undefined): void;
|
||||
download(remotePath: string, localPath: string, opts?: {} | undefined): void;
|
||||
delete(path: string): void;
|
||||
existsSync(path: string): boolean;
|
||||
isdirSync(path: string): boolean;
|
||||
uploadFolder(localPath: string, remotePath: string, opts?: {} | undefined): void;
|
||||
downloadFolder(remotePath: string, localPath: string, opts?: {} | undefined): void;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
"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 });
|
||||
class baseStorageNode {
|
||||
getinfo(path) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
listdir(path) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
makedir(path, mode) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
upload(localPath, remotePath, opts) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
download(remotePath, localPath, opts) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
delete(path) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
existsSync(path) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isdirSync(path) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
uploadFolder(localPath, remotePath, opts) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
downloadFolder(remotePath, localPath, opts) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
exports.baseStorageNode = baseStorageNode;
|
|
@ -1,31 +0,0 @@
|
|||
import { Identifiable } from '../commom/identifiable';
|
||||
/**
|
||||
* for some stable API calling (the results may not change for a long while)
|
||||
* the cache mechanism will help to reduce communication consumption
|
||||
*/
|
||||
export interface ICacheRecord {
|
||||
name: string;
|
||||
time: number;
|
||||
value: object | string | number;
|
||||
}
|
||||
/**
|
||||
* CacheClient will delegate some OpenPAIClient methods
|
||||
*/
|
||||
export declare class CacheClient extends Identifiable<ICacheRecord, string> {
|
||||
functions: {
|
||||
[index: string]: Function;
|
||||
};
|
||||
protected expiration: number;
|
||||
protected objects: {
|
||||
[index: string]: Object;
|
||||
};
|
||||
constructor(records?: ICacheRecord[]);
|
||||
setDaysToExpire(days: number): void;
|
||||
/**
|
||||
* register a method with Cache reading (e.g. storageClient.getStorageByName)
|
||||
* -> RecentlyUsedCacheInMemory().functions.getStorageByName(skipCache, name)
|
||||
* @param skipCache if true, will always call exec() to get new value and add a record
|
||||
*/
|
||||
delegate(thisArgs: Object, func: Function): void;
|
||||
protected uidOf(element: ICacheRecord): string;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const identifiable_1 = require("../commom/identifiable");
|
||||
const util_1 = require("../commom/util");
|
||||
function now() {
|
||||
return new Date().getTime();
|
||||
}
|
||||
function days2ms(days) {
|
||||
return 1000 * 3600 * 24 * days;
|
||||
}
|
||||
/**
|
||||
* CacheClient will delegate some OpenPAIClient methods
|
||||
*/
|
||||
class CacheClient extends identifiable_1.Identifiable {
|
||||
constructor(records) {
|
||||
super(records);
|
||||
this.functions = {};
|
||||
this.expiration = days2ms(7); // in unit of ms, default is 7 days
|
||||
this.objects = {};
|
||||
}
|
||||
setDaysToExpire(days) {
|
||||
this.expiration = days2ms(days);
|
||||
}
|
||||
/**
|
||||
* register a method with Cache reading (e.g. storageClient.getStorageByName)
|
||||
* -> RecentlyUsedCacheInMemory().functions.getStorageByName(skipCache, name)
|
||||
* @param skipCache if true, will always call exec() to get new value and add a record
|
||||
*/
|
||||
delegate(thisArgs, func) {
|
||||
if (func.name in this.objects) {
|
||||
throw new Error(`AlreadyBound: ${func.name}`);
|
||||
}
|
||||
this.objects[func.name] = thisArgs;
|
||||
this.functions[func.name] = async (skipCache, ...args) => {
|
||||
const name = [func.name].concat(args).join(':');
|
||||
util_1.Util.debug(`try to read (skipCache = ${skipCache}) the value of key ${name}`);
|
||||
if (!skipCache) {
|
||||
const idx = this.indexOf(name);
|
||||
if (idx > -1 && (now() - this.data[idx].time) < this.expiration) {
|
||||
util_1.Util.debug(`found valid cache created @ ${new Date(this.data[idx].time)}`);
|
||||
return this.data[idx].value;
|
||||
}
|
||||
}
|
||||
const value = await func.call(this.objects[func.name], ...args);
|
||||
this.add({ name: name, time: now(), value: value });
|
||||
util_1.Util.debug('no cached record found, create it', value);
|
||||
return value;
|
||||
};
|
||||
}
|
||||
uidOf(element) {
|
||||
return element.name;
|
||||
}
|
||||
}
|
||||
exports.CacheClient = CacheClient;
|
|
@ -1,69 +0,0 @@
|
|||
import { IPAICluster } from '../models/cluster';
|
||||
import { IJobConfig, IJobConfigV1 } from '../models/jobConfig';
|
||||
import { IJobInfo, IJobSshInfo, IJobStatus } from '../models/jobStatus';
|
||||
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<IJobStatus>;
|
||||
/**
|
||||
* 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 information, 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 information, will call /api/v1/jobs/${jobName}/ssh.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
getSshInfo(jobName: string): Promise<IJobSshInfo>;
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
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 JSON.parse(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;
|
|
@ -1,38 +0,0 @@
|
|||
import { AuthnClient } from '..';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
import { CacheClient, ICacheRecord } from './cacheClient';
|
||||
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;
|
||||
/**
|
||||
* OpenPAI cluster cache client
|
||||
*/
|
||||
cache: CacheClient;
|
||||
constructor(cluster: IPAICluster, cache?: ICacheRecord[]);
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const __1 = require("..");
|
||||
const baseClient_1 = require("./baseClient");
|
||||
const cacheClient_1 = require("./cacheClient");
|
||||
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, cache) {
|
||||
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);
|
||||
this.cache = new cacheClient_1.CacheClient(cache);
|
||||
this.cache.delegate(this.storage, this.storage.getStorages);
|
||||
this.cache.delegate(this.storage, this.storage.getStorageByName);
|
||||
}
|
||||
}
|
||||
exports.OpenPAIClient = OpenPAIClient;
|
|
@ -1,31 +0,0 @@
|
|||
import { IPAICluster } from '../models/cluster';
|
||||
import { IStorageConfig, IStorageDetail, IStorageServer, IStorageSummary } 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>;
|
||||
getStorages(token?: string): Promise<IStorageSummary>;
|
||||
getStorageByName(name: string, token?: string): Promise<IStorageDetail>;
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
// tslint:disable-next-line:match-default-export-name
|
||||
const axios_1 = require("axios");
|
||||
const util_1 = require("../commom/util");
|
||||
const baseClient_1 = require("./baseClient");
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
async getStorages(token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storages`, 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;
|
||||
}
|
||||
async getStorageByName(name, token) {
|
||||
const url = util_1.Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storages/${name}`, 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;
|
|
@ -1,25 +0,0 @@
|
|||
import { IStorageDetail } from '../models/storage';
|
||||
import { IFileInfo, IStorageNode, IStorageNodeClient } from '../models/storageOperation';
|
||||
/**
|
||||
* StorageNode class.
|
||||
*/
|
||||
export declare class StorageNode implements IStorageNode {
|
||||
config: IStorageDetail;
|
||||
client: IStorageNodeClient;
|
||||
constructor(config: IStorageDetail);
|
||||
/**
|
||||
* create client according to type.
|
||||
*/
|
||||
createClient(): IStorageNodeClient;
|
||||
getinfo(path: string): Promise<IFileInfo>;
|
||||
listdir(path: string): Promise<string[]>;
|
||||
makedir(path: string, mode?: string | undefined): Promise<void>;
|
||||
upload(localPath: string, remotePath: string, opts?: {} | undefined): Promise<void>;
|
||||
download(remotePath: string, localPath: string, opts?: {} | undefined): Promise<void>;
|
||||
delete(path: string): Promise<void>;
|
||||
existsSync(path: string): boolean;
|
||||
isdirSync(path: string): boolean;
|
||||
uploadFolder(localPath: string, remotePath: string, opts?: {} | undefined): Promise<void>;
|
||||
downloadFolder(remotePath: string, localPath: string, opts?: {} | undefined): Promise<void>;
|
||||
deleteFolder(path: string): Promise<void>;
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const __1 = require("..");
|
||||
/**
|
||||
* StorageNode class.
|
||||
*/
|
||||
class StorageNode {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.client = this.createClient();
|
||||
}
|
||||
/**
|
||||
* create client according to type.
|
||||
*/
|
||||
createClient() {
|
||||
switch (this.config.type) {
|
||||
case 'azureBlob': return new __1.AzureBlobClient(this.config);
|
||||
default: throw new Error(`NotImplemented`);
|
||||
}
|
||||
}
|
||||
async getinfo(path) {
|
||||
return this.client.getinfo(path);
|
||||
}
|
||||
async listdir(path) {
|
||||
return this.client.listdir(path);
|
||||
}
|
||||
async makedir(path, mode) {
|
||||
try {
|
||||
return this.client.makedir(path);
|
||||
}
|
||||
catch (e) {
|
||||
if (!this.client.mkdirAllowRecursive) {
|
||||
// do something recursively
|
||||
}
|
||||
}
|
||||
}
|
||||
async upload(localPath, remotePath, opts) {
|
||||
return this.client.upload(localPath, remotePath, opts);
|
||||
}
|
||||
async download(remotePath, localPath, opts) {
|
||||
return this.client.download(remotePath, localPath, opts);
|
||||
}
|
||||
async delete(path) {
|
||||
return this.client.delete(path);
|
||||
}
|
||||
existsSync(path) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
isdirSync(path) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
/* handle folder opation
|
||||
* if this.client has corresponding folder operation, use it
|
||||
* otherwise implement it recursively
|
||||
*/
|
||||
async uploadFolder(localPath, remotePath, opts) {
|
||||
if (this.client.uploadFolder) {
|
||||
return this.client.uploadFolder(localPath, remotePath, opts);
|
||||
}
|
||||
else {
|
||||
// TODO: handle upload recursively here
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
async downloadFolder(remotePath, localPath, opts) {
|
||||
if (this.client.downloadFolder) {
|
||||
return this.client.downloadFolder(remotePath, localPath, opts);
|
||||
}
|
||||
else {
|
||||
// TODO: handle download recursively here
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
async deleteFolder(path) {
|
||||
if (this.client.deleteFolder) {
|
||||
return this.client.deleteFolder(path);
|
||||
}
|
||||
else {
|
||||
// TODO: handle deletion recursively here
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.StorageNode = StorageNode;
|
|
@ -1,10 +0,0 @@
|
|||
import { StorageClient } from './storageClient';
|
||||
import { StorageNode } from './storageNode';
|
||||
/**
|
||||
* StorageOperation class
|
||||
*/
|
||||
export declare class StorageOperation {
|
||||
private client;
|
||||
constructor(client: StorageClient);
|
||||
getStorageNode(name: string, index?: number): Promise<StorageNode>;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
"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 storageNode_1 = require("./storageNode");
|
||||
/**
|
||||
* StorageOperation class
|
||||
*/
|
||||
class StorageOperation {
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
}
|
||||
async getStorageNode(name, index = 0) {
|
||||
const storageConfig = await this.client.getConfigByName(name);
|
||||
const mountInfo = storageConfig.mountInfos[index];
|
||||
const server = await this.client.getServerByName(mountInfo.server);
|
||||
return new storageNode_1.StorageNode(mountInfo, server);
|
||||
}
|
||||
}
|
||||
exports.StorageOperation = StorageOperation;
|
|
@ -1,104 +0,0 @@
|
|||
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;
|
||||
}
|
|
@ -1,228 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
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;
|
|
@ -1,47 +0,0 @@
|
|||
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>;
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
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;
|
|
@ -1,15 +0,0 @@
|
|||
import { IMountInfo, IStorageServer } from '../models/storage';
|
||||
import { IFileInfo, IStorageNodeClient } from '../models/storageOperation';
|
||||
/**
|
||||
* Web HDFS Client.
|
||||
*/
|
||||
export declare class WebHdfsClient implements IStorageNodeClient {
|
||||
mkdirAllowRecursive: boolean;
|
||||
constructor(config: IMountInfo, server: IStorageServer);
|
||||
getinfo(path: string): Promise<IFileInfo>;
|
||||
listdir(path: string): Promise<string[]>;
|
||||
makedir(path: string, mode?: string | undefined): Promise<void>;
|
||||
upload(localPath: string, remotePath: string, opts?: {} | undefined): Promise<void>;
|
||||
download(remotePath: string, localPath: string, opts?: {} | undefined): Promise<void>;
|
||||
delete(path: string): Promise<void>;
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/**
|
||||
* Web HDFS Client.
|
||||
*/
|
||||
class WebHdfsClient {
|
||||
constructor(config, server) {
|
||||
this.mkdirAllowRecursive = true;
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
async getinfo(path) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
async listdir(path) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
async makedir(path, mode) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
async upload(localPath, remotePath, opts) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
async download(remotePath, localPath, opts) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
async delete(path) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
exports.WebHdfsClient = WebHdfsClient;
|
|
@ -1,71 +0,0 @@
|
|||
import * as argparse from 'argparse';
|
||||
import { IPAICluster, OpenPAIClient } from '..';
|
||||
import { ICacheRecord } from '../client/cacheClient';
|
||||
import { Identifiable } from '../commom/identifiable';
|
||||
export interface IClusterWithCache {
|
||||
cluster: IPAICluster;
|
||||
cache?: ICacheRecord[];
|
||||
}
|
||||
interface ISubParserOptions extends argparse.SubArgumentParserOptions {
|
||||
name: string;
|
||||
}
|
||||
interface IArgumentOptions extends argparse.ArgumentOptions {
|
||||
name: string | string[];
|
||||
}
|
||||
interface IExclusiveArgGroup {
|
||||
required?: boolean;
|
||||
args: IArgumentOptions[];
|
||||
}
|
||||
/**
|
||||
* fix error TS2339: Property 'xxx' does not exist on type 'Namespace'.
|
||||
*/
|
||||
interface IArgument extends argparse.Namespace {
|
||||
[index: string]: any;
|
||||
}
|
||||
export interface IResult {
|
||||
command: string;
|
||||
args?: IArgument;
|
||||
result: any | undefined;
|
||||
}
|
||||
declare type CommandCallback = (a: IArgument) => any;
|
||||
declare type FormmaterCallback = (r: IResult) => void;
|
||||
/**
|
||||
* LocalClustersManager handles the prestored array of clusters and caches
|
||||
* by providing filtering, and client construction
|
||||
*/
|
||||
declare class LocalClustersManager extends Identifiable<IClusterWithCache, string> {
|
||||
getClusterConfig(alias: string): IPAICluster;
|
||||
getClusterClient(alias: string): OpenPAIClient;
|
||||
protected uidOf: (a: IClusterWithCache) => string;
|
||||
}
|
||||
/**
|
||||
* CliEngine is the executor of CLI commands processing
|
||||
*/
|
||||
export declare class CliEngine {
|
||||
manager: LocalClustersManager;
|
||||
protected clustersFileName?: string;
|
||||
protected parser: argparse.ArgumentParser;
|
||||
protected subparsers: argparse.SubParser;
|
||||
protected executors: {
|
||||
[index: string]: CommandCallback;
|
||||
};
|
||||
protected formatters: {
|
||||
[index: string]: FormmaterCallback;
|
||||
};
|
||||
constructor(input?: string | IClusterWithCache[]);
|
||||
load(): Promise<void>;
|
||||
store(): Promise<void>;
|
||||
/**
|
||||
* register a sub command to the CLI engine
|
||||
*/
|
||||
registerCommand(subCommand: ISubParserOptions, args: IArgumentOptions[], cb: CommandCallback, exclusiveArgs?: IExclusiveArgGroup[], formatter?: FormmaterCallback): void;
|
||||
/**
|
||||
* to evaluate a command (e.g. ['listj`, 'your-cluster1]) and return the result
|
||||
*/
|
||||
evaluate(params?: string[]): Promise<IResult>;
|
||||
/**
|
||||
* print the result with formatter to screen
|
||||
*/
|
||||
toScreen(result: IResult): void;
|
||||
}
|
||||
export {};
|
|
@ -1,134 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const argparse = require("argparse");
|
||||
const path = require("path");
|
||||
const __1 = require("..");
|
||||
const identifiable_1 = require("../commom/identifiable");
|
||||
const util_1 = require("../commom/util");
|
||||
const utils_1 = require("./utils");
|
||||
function defaultFommater(result) {
|
||||
const cout = (msg) => {
|
||||
if (typeof result.result === 'string') {
|
||||
console.log(result.result);
|
||||
}
|
||||
else {
|
||||
console.log(JSON.stringify(result.result || "", undefined, 4));
|
||||
}
|
||||
};
|
||||
cout(result.result || "");
|
||||
}
|
||||
/**
|
||||
* LocalClustersManager handles the prestored array of clusters and caches
|
||||
* by providing filtering, and client construction
|
||||
*/
|
||||
class LocalClustersManager extends identifiable_1.Identifiable {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.uidOf = (a) => a.cluster.alias;
|
||||
}
|
||||
getClusterConfig(alias) {
|
||||
const idx = this.indexOf(alias);
|
||||
if (idx > -1) {
|
||||
return this.data[idx].cluster;
|
||||
}
|
||||
throw new Error(`AliasNotFound: ${alias}`);
|
||||
}
|
||||
getClusterClient(alias) {
|
||||
const idx = this.indexOf(alias);
|
||||
if (idx > -1) {
|
||||
if (!this.data[idx].cache) {
|
||||
this.data[idx].cache = []; // ! link cache space with the client
|
||||
}
|
||||
return new __1.OpenPAIClient(this.data[idx].cluster, this.data[idx].cache);
|
||||
}
|
||||
throw new Error(`AliasNotFound: ${alias}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* CliEngine is the executor of CLI commands processing
|
||||
*/
|
||||
class CliEngine {
|
||||
constructor(input) {
|
||||
this.executors = {};
|
||||
this.formatters = {};
|
||||
this.manager = new LocalClustersManager();
|
||||
if (input) {
|
||||
if (typeof input === 'string') {
|
||||
this.clustersFileName = util_1.Util.expandUser(input);
|
||||
}
|
||||
else {
|
||||
this.manager.copyData(input);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.clustersFileName = util_1.Util.expandUser(path.join('~', '.openpai', 'clusters.json'));
|
||||
}
|
||||
this.parser = new argparse.ArgumentParser({
|
||||
version: '0.1',
|
||||
addHelp: true,
|
||||
description: 'command line tool for OpenPAI (github.com/microsoft/pai)'
|
||||
});
|
||||
this.subparsers = this.parser.addSubparsers({ title: 'commands', dest: 'subcommand' });
|
||||
}
|
||||
async load() {
|
||||
if (this.clustersFileName) {
|
||||
const data = await utils_1.readJson(this.clustersFileName, []);
|
||||
this.manager.assignData(data);
|
||||
}
|
||||
}
|
||||
async store() {
|
||||
if (this.clustersFileName) {
|
||||
await utils_1.writeJson(this.clustersFileName, this.manager.getData());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* register a sub command to the CLI engine
|
||||
*/
|
||||
registerCommand(subCommand, args, cb, exclusiveArgs, formatter) {
|
||||
const addArgument = (ps, a) => {
|
||||
const name = a.name;
|
||||
delete a.name;
|
||||
ps.addArgument(name, a);
|
||||
};
|
||||
const cmd = subCommand.name;
|
||||
delete subCommand.name;
|
||||
if (subCommand.addHelp == null) { // null or undefined
|
||||
subCommand.addHelp = true;
|
||||
}
|
||||
const parser = this.subparsers.addParser(cmd, subCommand);
|
||||
for (const arg of args) {
|
||||
addArgument(parser, arg);
|
||||
}
|
||||
if (exclusiveArgs) {
|
||||
for (const g of exclusiveArgs) {
|
||||
const group = parser.addMutuallyExclusiveGroup({ required: g.required || false });
|
||||
for (const arg of g.args) {
|
||||
addArgument(group, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.executors[cmd] = cb;
|
||||
this.formatters[cmd] = formatter || defaultFommater;
|
||||
}
|
||||
/**
|
||||
* to evaluate a command (e.g. ['listj`, 'your-cluster1]) and return the result
|
||||
*/
|
||||
async evaluate(params) {
|
||||
const args = this.parser.parseArgs(params);
|
||||
const cmd = args.subcommand;
|
||||
delete args.subcommand;
|
||||
util_1.Util.debug(cmd, args);
|
||||
const result = await Promise.resolve(this.executors[cmd](args));
|
||||
return { command: cmd, args: args, result: result };
|
||||
}
|
||||
/**
|
||||
* print the result with formatter to screen
|
||||
*/
|
||||
toScreen(result) {
|
||||
util_1.Util.debug('results received', result);
|
||||
this.formatters[result.command](result);
|
||||
}
|
||||
}
|
||||
exports.CliEngine = CliEngine;
|
|
@ -1,5 +0,0 @@
|
|||
import { CliEngine } from './cliEngine';
|
||||
/**
|
||||
* register commands related to cluster management
|
||||
*/
|
||||
export declare const registerClusterCommands: (cli: CliEngine) => void;
|
|
@ -1,37 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const __1 = require("..");
|
||||
const utils_1 = require("./utils");
|
||||
/**
|
||||
* register commands related to cluster management
|
||||
*/
|
||||
exports.registerClusterCommands = (cli) => {
|
||||
cli.registerCommand({ name: 'listc', help: 'list clusters' }, [], (a) => {
|
||||
const result = cli.manager.getData();
|
||||
return result.map((x) => x.cluster);
|
||||
}, undefined, (r) => {
|
||||
const clusters = r.result;
|
||||
const rows = [
|
||||
['alias', 'uri', 'user', 'https']
|
||||
];
|
||||
clusters.forEach(cluster => rows.push([
|
||||
cluster.alias, cluster.pai_uri, cluster.username, cluster.https
|
||||
]));
|
||||
utils_1.table2Console(rows);
|
||||
});
|
||||
cli.registerCommand({ name: 'addc', help: 'add cluster' }, [
|
||||
{ name: 'pai_uri', help: 'url of OpenPAI cluster like http(s)://x.x.x' },
|
||||
{ name: 'username' },
|
||||
{ name: 'token' },
|
||||
{ name: ['--alias', '-a'], help: 'cluster alias' }
|
||||
], (a) => {
|
||||
cli.manager.add({ cluster: __1.OpenPAIClient.parsePaiUri(a) });
|
||||
});
|
||||
cli.registerCommand({ name: 'delc', help: 'delete cluster' }, [
|
||||
{ name: 'alias', help: 'alias to remove' }
|
||||
], (a) => {
|
||||
cli.manager.remove(a.alias);
|
||||
});
|
||||
};
|
|
@ -1,6 +0,0 @@
|
|||
import { CliEngine } from './cliEngine';
|
||||
/**
|
||||
* register all sub commands
|
||||
*/
|
||||
declare const registerBuiltinCommands: (cli: CliEngine) => void;
|
||||
export { CliEngine, registerBuiltinCommands };
|
|
@ -1,18 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const cliEngine_1 = require("./cliEngine");
|
||||
exports.CliEngine = cliEngine_1.CliEngine;
|
||||
const clusterCommands_1 = require("./clusterCommands");
|
||||
const jobCommands_1 = require("./jobCommands");
|
||||
const storageCommands_1 = require("./storageCommands");
|
||||
/**
|
||||
* register all sub commands
|
||||
*/
|
||||
const registerBuiltinCommands = (cli) => {
|
||||
clusterCommands_1.registerClusterCommands(cli);
|
||||
jobCommands_1.registerJobCommands(cli);
|
||||
storageCommands_1.registerStorageCommands(cli);
|
||||
};
|
||||
exports.registerBuiltinCommands = registerBuiltinCommands;
|
|
@ -1,5 +0,0 @@
|
|||
import { CliEngine } from './cliEngine';
|
||||
/**
|
||||
* register job realted commands
|
||||
*/
|
||||
export declare function registerJobCommands(cli: CliEngine): void;
|
|
@ -1,84 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const yaml = require("js-yaml");
|
||||
const fs = require("fs-extra");
|
||||
const util_1 = require("../commom/util");
|
||||
const utils_1 = require("./utils");
|
||||
const assert = require("assert");
|
||||
/**
|
||||
* register job realted commands
|
||||
*/
|
||||
function registerJobCommands(cli) {
|
||||
cli.registerCommand({ name: 'listj', help: 'list jobs', aliases: ['list-jobs'] }, [
|
||||
{ name: 'alias', help: 'cluster alias' }
|
||||
], async (a) => {
|
||||
const client = cli.manager.getClusterClient(a.alias);
|
||||
if (a.all) {
|
||||
return client.job.list();
|
||||
}
|
||||
return client.job.list(`username=${a.user || client.config.username()}`);
|
||||
}, [
|
||||
{
|
||||
args: [
|
||||
{ name: ['--user', '-u'], help: 'username (default is user in cluster config)' },
|
||||
{ name: ['--all', '-a'], help: 'list jobs from all users', action: 'storeTrue' }
|
||||
]
|
||||
}
|
||||
], (r) => {
|
||||
const jobs = r.result;
|
||||
const rows = [
|
||||
['name', 'user', 'state', 'VC', '#GPU', '#Task', 'createdTime', 'completedTime']
|
||||
];
|
||||
jobs.forEach(job => rows.push([
|
||||
job.name, job.username, job.state, job.virtualCluster,
|
||||
job.totalGpuNumber, job.totalTaskNumber,
|
||||
new Date(job.createdTime).toLocaleString(), new Date(job.completedTime).toLocaleString()
|
||||
]));
|
||||
utils_1.table2Console(rows);
|
||||
});
|
||||
cli.registerCommand({ name: 'subj', help: "submit job" }, [
|
||||
{ name: 'alias', help: 'cluster alias' },
|
||||
{ name: 'cfgfile', help: 'config file' }
|
||||
], async (a) => {
|
||||
const client = cli.manager.getClusterClient(a.alias);
|
||||
const config = yaml.safeLoad(fs.readFileSync(util_1.Util.expandUser(a.cfgfile), 'utf8'));
|
||||
return client.job.submit(config);
|
||||
});
|
||||
cli.registerCommand({ name: 'getj', help: "get job details", aliases: ['job-info'] }, [
|
||||
{ name: ['--user'], help: 'username' },
|
||||
{ name: 'alias', help: 'cluster alias' },
|
||||
{ name: 'job', help: 'config file' },
|
||||
], async (a) => {
|
||||
const client = cli.manager.getClusterClient(a.alias);
|
||||
return client.job.getFrameworkInfo(a.user || client.config.username(), a.job);
|
||||
});
|
||||
cli.registerCommand({ name: 'ssh', help: 'ssh to the job container' }, [
|
||||
{ name: ['--user'], help: 'username on the openpai cluster' },
|
||||
{ name: ['--login-name', '-l'], help: 'the username to login as on the remote machine', defaultValue: 'root' },
|
||||
{ name: ['--identity-file', '-i'], help: 'the file to load identity (private key)' },
|
||||
{ name: 'alias', help: 'cluster alias' },
|
||||
{ name: 'job', help: 'config file' },
|
||||
{ name: 'taskrole', help: 'task role', nargs: '?' },
|
||||
{ name: 'taskindex', help: 'task index', nargs: '?' }
|
||||
], async (a) => {
|
||||
const client = cli.manager.getClusterClient(a.alias);
|
||||
const jobinfo = await client.job.getFrameworkInfo(a.user || client.config.username(), a.job);
|
||||
a.taskrole = a.taskrole || Object.keys(jobinfo.taskRoles)[0];
|
||||
a.taskindex = a.taskindex || 0;
|
||||
const container = jobinfo.taskRoles[a.taskrole].taskStatuses[a.taskindex];
|
||||
assert('ssh' in container.containerPorts, `ssh port is not declared when submitting`);
|
||||
const cmd = ['ssh', '-oStrictHostKeyChecking=no'];
|
||||
if (a.identity_file) {
|
||||
cmd.push('-i', a.identity_file);
|
||||
}
|
||||
if (a.login_name) {
|
||||
cmd.push('-l', a.login_name);
|
||||
}
|
||||
cmd.push('-p', container.containerPorts['ssh']);
|
||||
cmd.push(container.containerIp);
|
||||
return (cmd.join(' '));
|
||||
});
|
||||
}
|
||||
exports.registerJobCommands = registerJobCommands;
|
|
@ -1,5 +0,0 @@
|
|||
import { CliEngine } from './cliEngine';
|
||||
/**
|
||||
* register storage related commands
|
||||
*/
|
||||
export declare function registerStorageCommands(cli: CliEngine): void;
|
|
@ -1,25 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/**
|
||||
* register storage related commands
|
||||
*/
|
||||
function registerStorageCommands(cli) {
|
||||
cli.registerCommand({ name: 'lists', help: 'list storages', aliases: ['list-storages'] }, [
|
||||
{ name: 'alias', help: 'cluster alias' },
|
||||
{ name: ['--skip-cache', '-k'], help: 'skip cached record, fetch latest value', action: 'storeTrue' }
|
||||
], async (a) => {
|
||||
const client = cli.manager.getClusterClient(a.alias);
|
||||
return await client.cache.functions.getStorages(a.skip_cache);
|
||||
});
|
||||
cli.registerCommand({ name: 'getinfo', help: 'get info of destination path in storage' }, [
|
||||
{ name: 'alias', help: 'cluster alias' },
|
||||
{ name: 'storage', help: 'storage name' },
|
||||
{ name: ['--skip-cache', '-k'], help: 'skip cached record, fetch latest value', action: 'storeTrue' }
|
||||
], async (a) => {
|
||||
const client = cli.manager.getClusterClient(a.alias);
|
||||
return await client.cache.functions.getStorageByName(a.skip_cache, a.storage);
|
||||
});
|
||||
}
|
||||
exports.registerStorageCommands = registerStorageCommands;
|
|
@ -1,6 +0,0 @@
|
|||
/**
|
||||
* utils functions
|
||||
*/
|
||||
export declare function readJson<T extends object>(pth: string, val?: T): Promise<T>;
|
||||
export declare function writeJson<T extends object>(pth: string, val: T): Promise<void>;
|
||||
export declare function table2Console(rows: any[][]): void;
|
|
@ -1,40 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs = require("fs-extra");
|
||||
const path_1 = require("path");
|
||||
const util_1 = require("../commom/util");
|
||||
const table_1 = require("table");
|
||||
/**
|
||||
* utils functions
|
||||
*/
|
||||
async function readJson(pth, val) {
|
||||
try {
|
||||
const data = await fs.readJson(pth);
|
||||
util_1.Util.debug(`data loaded from ${pth}`, data);
|
||||
return data;
|
||||
}
|
||||
catch (e) {
|
||||
console.warn(e.message);
|
||||
if (val == null) {
|
||||
throw new Error(e);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
exports.readJson = readJson;
|
||||
async function writeJson(pth, val) {
|
||||
await fs.ensureDir(path_1.dirname(pth));
|
||||
await fs.writeJSON(pth, val);
|
||||
util_1.Util.debug(`saved to ${pth}`);
|
||||
}
|
||||
exports.writeJson = writeJson;
|
||||
function table2Console(rows) {
|
||||
const config = {
|
||||
border: table_1.getBorderCharacters(`ramac`)
|
||||
};
|
||||
const output = table_1.table(rows, config);
|
||||
console.log(output);
|
||||
}
|
||||
exports.table2Console = table2Console;
|
|
@ -1,16 +0,0 @@
|
|||
/**
|
||||
* the container for identifiable objects(:T) with unique ID (:U)
|
||||
*/
|
||||
export declare abstract class Identifiable<T, U> {
|
||||
protected data: T[];
|
||||
constructor(data?: T[]);
|
||||
getData: () => T[];
|
||||
copyData(data: T[]): void;
|
||||
assignData(data: T[]): void;
|
||||
identities(): U[];
|
||||
indexOf(uid: U): number;
|
||||
add(element: T, denyIfExists?: boolean): void;
|
||||
remove(uid: U): void;
|
||||
protected abstract uidOf(element: T): U;
|
||||
protected uidEq(element: T, uid: U): boolean;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/**
|
||||
* the container for identifiable objects(:T) with unique ID (:U)
|
||||
*/
|
||||
class Identifiable {
|
||||
constructor(data) {
|
||||
this.data = [];
|
||||
this.getData = () => this.data;
|
||||
if (data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
copyData(data) {
|
||||
this.data = JSON.parse(JSON.stringify(data));
|
||||
}
|
||||
assignData(data) {
|
||||
Object.assign(this.data, data);
|
||||
}
|
||||
identities() {
|
||||
return this.data.map((a) => {
|
||||
return this.uidOf(a);
|
||||
});
|
||||
}
|
||||
indexOf(uid) {
|
||||
return this.identities().indexOf(uid);
|
||||
}
|
||||
add(element, denyIfExists = false) {
|
||||
const uid = this.uidOf(element);
|
||||
if (uid == null) {
|
||||
throw new Error(`UnIdentifiable`);
|
||||
}
|
||||
const idx = this.indexOf(uid);
|
||||
if (denyIfExists && idx > -1) {
|
||||
throw new Error(`AlreadyExists: of ${this.uidOf(element)}`);
|
||||
}
|
||||
if (idx === -1) {
|
||||
this.data.push(element);
|
||||
}
|
||||
else {
|
||||
this.data[idx] = element;
|
||||
}
|
||||
}
|
||||
remove(uid) {
|
||||
const idx = this.indexOf(uid);
|
||||
if (idx > -1) {
|
||||
this.data.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
uidEq(element, uid) {
|
||||
return this.uidOf(element) === uid;
|
||||
}
|
||||
}
|
||||
exports.Identifiable = Identifiable;
|
|
@ -1,12 +0,0 @@
|
|||
/**
|
||||
* Utility class.
|
||||
*/
|
||||
declare class UtilClass {
|
||||
https: boolean;
|
||||
debugMode: boolean;
|
||||
fixUrl(url: string, https?: boolean): string;
|
||||
expandUser(url: string): string;
|
||||
debug(msg?: string, obj?: object): void;
|
||||
}
|
||||
export declare const Util: UtilClass;
|
||||
export {};
|
|
@ -1,43 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/**
|
||||
* Utility class.
|
||||
*/
|
||||
class UtilClass {
|
||||
constructor() {
|
||||
this.https = false;
|
||||
this.debugMode = false;
|
||||
}
|
||||
fixUrl(url, https) {
|
||||
if (!/^[a-zA-Z]+?\:\/\//.test(url)) {
|
||||
url = `http${https ? 's' : ''}://` + url;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
expandUser(url) {
|
||||
if (/~/.test(url)) {
|
||||
const home = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
|
||||
if (home) {
|
||||
url = url.replace('~', home);
|
||||
}
|
||||
else {
|
||||
throw new Error(`could not resolve ~ for ${url}`);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
debug(msg, obj) {
|
||||
if (!this.debugMode) {
|
||||
return;
|
||||
}
|
||||
if (msg) {
|
||||
console.debug(msg);
|
||||
}
|
||||
if (obj) {
|
||||
console.debug(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.Util = new UtilClass();
|
|
@ -1,17 +0,0 @@
|
|||
import { AuthnClient } from './client/authnClient';
|
||||
import { AzureBlobClient } from './client/azureBlobClient';
|
||||
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 } from './models/jobConfig';
|
||||
import { IJobFrameworkInfo, IJobInfo, IJobSshInfo, IJobStatus } from './models/jobStatus';
|
||||
import { IMountInfo, IStorageConfig, IStorageDetail, IStorageServer, IStorageSummary } from './models/storage';
|
||||
import { IFileInfo } from './models/storageOperation';
|
||||
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, IStorageSummary, IStorageDetail, IMountInfo, IJobStatus, AzureBlobClient, IFileInfo };
|
19
lib/index.js
19
lib/index.js
|
@ -1,19 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
// tslint:disable-next-line:missing-jsdoc
|
||||
const authnClient_1 = require("./client/authnClient");
|
||||
exports.AuthnClient = authnClient_1.AuthnClient;
|
||||
const azureBlobClient_1 = require("./client/azureBlobClient");
|
||||
exports.AzureBlobClient = azureBlobClient_1.AzureBlobClient;
|
||||
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;
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
* OpenPAI cluster.
|
||||
*/
|
||||
export interface IPAICluster {
|
||||
info?: IPAIClusterInfo;
|
||||
alias?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
token?: string;
|
||||
https?: boolean;
|
||||
pai_uri?: string;
|
||||
rest_server_uri?: string;
|
||||
grafana_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';
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -1,213 +0,0 @@
|
|||
/**
|
||||
* 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?: {
|
||||
/** 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?: {
|
||||
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;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -1,164 +0,0 @@
|
|||
/**
|
||||
* 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.
|
||||
* https://github.com/microsoft/openpai-protocol/blob/master/schemas/v2/schema.yaml
|
||||
*/
|
||||
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?: {
|
||||
/** 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?: {
|
||||
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;
|
||||
};
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -1,118 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
export interface IAppExitSpec {
|
||||
code: number;
|
||||
phrase: string;
|
||||
issuer: string;
|
||||
causer: string;
|
||||
type: string;
|
||||
stage: string;
|
||||
behavior: string;
|
||||
reaction: string;
|
||||
repro: string[];
|
||||
}
|
||||
export interface IJobStatusDetails {
|
||||
username: string;
|
||||
state: 'WAITING' | 'RUNNING' | 'SUCCEEDED' | 'STOPPED' | 'FAILED' | 'UNKNOWN';
|
||||
subState: string;
|
||||
executionType: 'START' | 'STOP';
|
||||
retries: number;
|
||||
retryDetails: {
|
||||
user?: number;
|
||||
platform?: number;
|
||||
resource?: number;
|
||||
};
|
||||
retryDelayTime?: any;
|
||||
createdTime: number;
|
||||
completedTime: number | null;
|
||||
appId: string;
|
||||
appProgress: number;
|
||||
appTrackingUrl: string;
|
||||
appLaunchedTime: number | null;
|
||||
appCompletedTime: number | null;
|
||||
appExitCode: number | null;
|
||||
appExitSpec: IAppExitSpec | null;
|
||||
appExitDiagnostics: string | null;
|
||||
appExitMessages: {
|
||||
container?: string | null;
|
||||
runtime?: string | null;
|
||||
launcher?: string | null;
|
||||
} | null;
|
||||
appExitTriggerMessage: string | null;
|
||||
appExitTriggerTaskRoleName: string | null;
|
||||
appExitTriggerTaskIndex: number | null;
|
||||
appExitType: string | null;
|
||||
virtualCluster: string | null;
|
||||
}
|
||||
export interface ITaskStatus {
|
||||
taskIndex: number;
|
||||
taskState: string;
|
||||
containerId: string;
|
||||
containerIp: string;
|
||||
containerPorts: {
|
||||
[index: string]: number | number[] | string;
|
||||
};
|
||||
containerGpus?: any;
|
||||
containerLog: string;
|
||||
containerExitCode: number | null;
|
||||
hived?: {
|
||||
affinityGroupName?: any;
|
||||
lazyPreempted?: any;
|
||||
lazyPreemptionStatus?: any;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* OpenPAI Job status.
|
||||
*/
|
||||
export interface IJobStatus {
|
||||
name: string;
|
||||
jobStatus: IJobStatusDetails;
|
||||
taskRoles: {
|
||||
[index: string]: {
|
||||
taskRoleStatus: {
|
||||
name: string;
|
||||
};
|
||||
taskStatuses: ITaskStatus[];
|
||||
};
|
||||
};
|
||||
}
|
||||
/**
|
||||
* OpenPAI Job Framework Infomation.
|
||||
*/
|
||||
export interface IJobFrameworkInfo {
|
||||
summarizedFrameworkInfo?: any | null;
|
||||
aggregatedFrameworkRequest?: any | null;
|
||||
aggregatedFrameworkStatus?: any | null;
|
||||
}
|
||||
/**
|
||||
* OpenPAI Job SSH Information.
|
||||
*/
|
||||
export interface IJobSshInfo {
|
||||
containers?: any | null;
|
||||
keyPair?: any | null;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* OpenPAI storage information.
|
||||
*/
|
||||
export interface IStorageServer {
|
||||
spn: string;
|
||||
type: 'nfs' | 'samba' | 'azurefile' | 'azureblob' | 'hdfs' | 'other';
|
||||
data: {
|
||||
[prop: string]: any;
|
||||
};
|
||||
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;
|
||||
}
|
||||
export interface IStorageSummaryItem {
|
||||
name: string;
|
||||
share: boolean;
|
||||
volumeName: string;
|
||||
}
|
||||
export interface IStorageSummary {
|
||||
storages: IStorageSummaryItem[];
|
||||
}
|
||||
export interface INfsCfg {
|
||||
server: string;
|
||||
path: string;
|
||||
}
|
||||
export interface ISambaCfg {
|
||||
address: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
}
|
||||
export interface IAzureFileCfg {
|
||||
shareName: string;
|
||||
accountName?: string;
|
||||
accountKey?: string;
|
||||
}
|
||||
export interface IAzureBlobCfg {
|
||||
containerName: string;
|
||||
accountName?: string;
|
||||
accountKey?: string;
|
||||
accountSASToken?: string;
|
||||
}
|
||||
export interface IStorageDetail extends IStorageSummaryItem {
|
||||
type: 'nfs' | 'samba' | 'azureFile' | 'azureBlob' | 'other' | 'unknown';
|
||||
data: INfsCfg | ISambaCfg | IAzureBlobCfg | IAzureFileCfg | Object;
|
||||
secretName?: string;
|
||||
mountOptions?: string[];
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* An abstract File System based on file operation
|
||||
*/
|
||||
import { IStorageDetail } from './storage';
|
||||
export interface IFileInfo {
|
||||
mode: string;
|
||||
owner: string;
|
||||
group: string;
|
||||
size: number;
|
||||
blksize: number;
|
||||
type: 'file' | 'directory';
|
||||
atime: Date;
|
||||
mtime: Date;
|
||||
}
|
||||
export interface IStorageNode {
|
||||
config: IStorageDetail;
|
||||
client?: IStorageNodeClient;
|
||||
getinfo(path: string): Promise<IFileInfo>;
|
||||
listdir(path: string): Promise<string[]>;
|
||||
makedir(path: string, mode?: string): Promise<void>;
|
||||
upload(localPath: string, remotePath: string, opts?: {}): Promise<void>;
|
||||
download(remotePath: string, localPath: string, opts?: {}): Promise<void>;
|
||||
delete(path: string): Promise<void>;
|
||||
existsSync(path: string): boolean;
|
||||
isdirSync(path: string): boolean;
|
||||
uploadFolder(localPath: string, remotePath: string, opts?: {}): Promise<void>;
|
||||
downloadFolder(remotePath: string, localPath: string, opts?: {}): Promise<void>;
|
||||
deleteFolder(path: string): Promise<void>;
|
||||
}
|
||||
export interface IStorageNodeClient {
|
||||
mkdirAllowRecursive: boolean;
|
||||
getinfo(path: string): Promise<IFileInfo>;
|
||||
listdir(path: string): Promise<string[]>;
|
||||
makedir(path: string, mode?: string): Promise<void>;
|
||||
upload(localPath: string, remotePath: string, opts?: {}): Promise<void>;
|
||||
download(remotePath: string, localPath: string, opts?: {}): Promise<void>;
|
||||
delete(path: string): Promise<void>;
|
||||
uploadFolder?(localPath: string, remotePath: string, opts?: {}): Promise<void>;
|
||||
downloadFolder?(remotePath: string, localPath: string, opts?: {}): Promise<void>;
|
||||
deleteFolder?(path: string): Promise<void>;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -1,7 +0,0 @@
|
|||
/**
|
||||
* OpenPAI access token.
|
||||
*/
|
||||
export interface ITokenItem {
|
||||
token: string;
|
||||
expireTime: number;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -1,11 +0,0 @@
|
|||
/**
|
||||
* OpenPAI User Info.
|
||||
*/
|
||||
export interface IUserInfo {
|
||||
username?: string | null;
|
||||
grouplist?: string[] | null;
|
||||
email?: string | null;
|
||||
extension?: any | null;
|
||||
admin?: boolean;
|
||||
virtualCluster?: string[] | null;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "openpai-js-sdk",
|
||||
"name": "@microsoft/openpai-js-sdk",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
|
@ -112,14 +112,20 @@
|
|||
"@babel/highlight": "^7.8.3"
|
||||
}
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz",
|
||||
"integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
|
||||
"integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
|
||||
"integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.9.0",
|
||||
"chalk": "^2.0.0",
|
||||
"esutils": "^2.0.2",
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
|
@ -185,6 +191,12 @@
|
|||
"integrity": "sha512-0CFu/g4mDSNkodVwWijdlr8jH7RoplRWNgovjFLEZeT+QEbbZXjBmCe3HwaWheAlCbHwomTwzZoSedeOycABug==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mocha": {
|
||||
"version": "5.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
|
||||
|
@ -572,20 +584,6 @@
|
|||
"type-detect": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"deep-equal": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
|
||||
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-arguments": "^1.0.4",
|
||||
"is-date-object": "^1.0.1",
|
||||
"is-regex": "^1.0.4",
|
||||
"object-is": "^1.0.1",
|
||||
"object-keys": "^1.1.1",
|
||||
"regexp.prototype.flags": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"define-properties": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
|
||||
|
@ -627,9 +625,9 @@
|
|||
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
|
||||
},
|
||||
"es-abstract": {
|
||||
"version": "1.17.4",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
|
||||
"integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==",
|
||||
"version": "1.17.5",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
|
||||
"integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es-to-primitive": "^1.2.1",
|
||||
|
@ -667,12 +665,6 @@
|
|||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"dev": true
|
||||
},
|
||||
"events": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
|
||||
|
@ -878,12 +870,6 @@
|
|||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
|
||||
"integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
|
||||
},
|
||||
"is-arguments": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
|
||||
"integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
|
||||
"dev": true
|
||||
},
|
||||
"is-buffer": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
|
||||
|
@ -976,6 +962,15 @@
|
|||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
||||
},
|
||||
"json5": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
|
@ -1053,27 +1048,10 @@
|
|||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"mocha": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz",
|
||||
"integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==",
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz",
|
||||
"integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-colors": "3.2.3",
|
||||
|
@ -1088,7 +1066,7 @@
|
|||
"js-yaml": "3.13.1",
|
||||
"log-symbols": "2.2.0",
|
||||
"minimatch": "3.0.4",
|
||||
"mkdirp": "0.5.1",
|
||||
"mkdirp": "0.5.4",
|
||||
"ms": "2.1.1",
|
||||
"node-environment-flags": "1.0.5",
|
||||
"object.assign": "4.1.0",
|
||||
|
@ -1096,8 +1074,8 @@
|
|||
"supports-color": "6.0.0",
|
||||
"which": "1.3.1",
|
||||
"wide-align": "1.1.3",
|
||||
"yargs": "13.3.0",
|
||||
"yargs-parser": "13.1.1",
|
||||
"yargs": "13.3.2",
|
||||
"yargs-parser": "13.1.2",
|
||||
"yargs-unparser": "1.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -1110,6 +1088,15 @@
|
|||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz",
|
||||
"integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||
|
@ -1130,20 +1117,15 @@
|
|||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"nock": {
|
||||
"version": "10.0.6",
|
||||
"resolved": "https://registry.npmjs.org/nock/-/nock-10.0.6.tgz",
|
||||
"integrity": "sha512-b47OWj1qf/LqSQYnmokNWM8D88KvUl2y7jT0567NB3ZBAZFz2bWp2PC81Xn7u8F2/vJxzkzNZybnemeFa7AZ2w==",
|
||||
"version": "12.0.3",
|
||||
"resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz",
|
||||
"integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chai": "^4.1.2",
|
||||
"debug": "^4.1.0",
|
||||
"deep-equal": "^1.0.0",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"lodash": "^4.17.5",
|
||||
"mkdirp": "^0.5.0",
|
||||
"propagate": "^1.0.0",
|
||||
"qs": "^6.5.1",
|
||||
"semver": "^5.5.0"
|
||||
"lodash": "^4.17.13",
|
||||
"propagate": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
|
@ -1189,12 +1171,6 @@
|
|||
"integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==",
|
||||
"dev": true
|
||||
},
|
||||
"object-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz",
|
||||
"integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==",
|
||||
"dev": true
|
||||
},
|
||||
"object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
|
@ -1233,9 +1209,9 @@
|
|||
}
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
|
||||
"integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
|
@ -1297,9 +1273,9 @@
|
|||
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
|
||||
},
|
||||
"propagate": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz",
|
||||
"integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz",
|
||||
"integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==",
|
||||
"dev": true
|
||||
},
|
||||
"psl": {
|
||||
|
@ -1317,16 +1293,6 @@
|
|||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"regexp.prototype.flags": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
|
||||
"integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.0-next.1"
|
||||
}
|
||||
},
|
||||
"request": {
|
||||
"version": "2.88.2",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
|
||||
|
@ -1514,24 +1480,46 @@
|
|||
"strip-ansi": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimleft": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
|
||||
"integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
|
||||
"string.prototype.trimend": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
|
||||
"integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"function-bind": "^1.1.1"
|
||||
"es-abstract": "^1.17.5"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimleft": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
|
||||
"integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.5",
|
||||
"string.prototype.trimstart": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimright": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
|
||||
"integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
|
||||
"integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"function-bind": "^1.1.1"
|
||||
"es-abstract": "^1.17.5",
|
||||
"string.prototype.trimend": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimstart": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
|
||||
"integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.5"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
|
@ -1543,6 +1531,12 @@
|
|||
"ansi-regex": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
|
||||
"dev": true
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
|
@ -1625,15 +1619,27 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"tsconfig-paths": {
|
||||
"version": "3.9.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
|
||||
"integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json5": "^0.0.29",
|
||||
"json5": "^1.0.1",
|
||||
"minimist": "^1.2.0",
|
||||
"strip-bom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.0.tgz",
|
||||
"integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg=="
|
||||
},
|
||||
"tslint": {
|
||||
"version": "5.20.1",
|
||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz",
|
||||
"integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==",
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.1.tgz",
|
||||
"integrity": "sha512-kd6AQ/IgPRpLn6g5TozqzPdGNZ0q0jtXW4//hRcj10qLYBaa3mTUU2y2MCG+RXZm8Zx+KZi0eA+YCrMyNlF4UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
|
@ -1644,10 +1650,10 @@
|
|||
"glob": "^7.1.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"minimatch": "^3.0.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mkdirp": "^0.5.3",
|
||||
"resolve": "^1.3.2",
|
||||
"semver": "^5.3.0",
|
||||
"tslib": "^1.8.0",
|
||||
"tslib": "^1.10.0",
|
||||
"tsutils": "^2.29.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -1656,6 +1662,15 @@
|
|||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1842,9 +1857,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "13.3.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
|
||||
"integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
|
||||
"version": "13.3.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
|
||||
"integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cliui": "^5.0.0",
|
||||
|
@ -1856,7 +1871,7 @@
|
|||
"string-width": "^3.0.0",
|
||||
"which-module": "^2.0.0",
|
||||
"y18n": "^4.0.0",
|
||||
"yargs-parser": "^13.1.1"
|
||||
"yargs-parser": "^13.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
|
@ -1888,9 +1903,9 @@
|
|||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "13.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
|
||||
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
|
||||
"version": "13.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
|
||||
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^5.0.0",
|
||||
|
|
14
package.json
14
package.json
|
@ -10,7 +10,10 @@
|
|||
"scripts": {
|
||||
"format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
|
||||
"lint": "tslint -p tsconfig.json",
|
||||
"test": "mocha -r ts-node/register tests/**/*.spec.ts"
|
||||
"pretest": "tslint --config tslint.json --project tsconfig.json",
|
||||
"test": "mocha -r ts-node/register -r tsconfig-paths/register tests/**/*.spec.ts",
|
||||
"prebuild": "tslint --config tslint.json --project tsconfig.json",
|
||||
"build": "tsc -p tsconfig.build.json"
|
||||
},
|
||||
"homepage": "https://github.com/Microsoft/openpaisdk",
|
||||
"repository": {
|
||||
|
@ -37,12 +40,13 @@
|
|||
"chai": "^4.2.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"minimist": ">=1.2.2",
|
||||
"mocha": "^6.2.0",
|
||||
"mocha": "^6.2.3",
|
||||
"mock-fs": "^4.11.0",
|
||||
"nock": "^10.0.6",
|
||||
"nock": "^12.0.3",
|
||||
"prettier": "^1.18.2",
|
||||
"ts-node": "^8.3.0",
|
||||
"tslint": "^5.18.0",
|
||||
"tsconfig-paths": "^3.9.0",
|
||||
"tslint": "^6.1.1",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"tslint-microsoft-contrib": "^6.2.0",
|
||||
"typescript": "^3.5.3"
|
||||
|
@ -50,7 +54,7 @@
|
|||
"dependencies": {
|
||||
"@azure/storage-blob": "^12.1.0",
|
||||
"argparse": "^1.0.10",
|
||||
"axios": "^0.19.0",
|
||||
"axios": "^0.19.2",
|
||||
"fs-extra": "^8.1.0",
|
||||
"js-yaml": "^3.13.1",
|
||||
"request": "^2.88.0",
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import * as ApiV1 from './v1';
|
||||
import * as ApiV2 from './v2';
|
||||
|
||||
/**
|
||||
* Export
|
||||
*/
|
||||
export {
|
||||
ApiV1,
|
||||
ApiV2
|
||||
};
|
|
@ -1,12 +1,10 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IAuthnInfo, IPAICluster } from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
import * as request from 'request-promise-native';
|
||||
|
||||
import { Util } from '../commom/util';
|
||||
import { IAuthnInfo } from '../models/authn';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
|
@ -23,7 +21,7 @@ export class AuthnClient extends OpenPAIBaseClient {
|
|||
* Get authn information.
|
||||
*/
|
||||
public async info(): Promise<IAuthnInfo> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/info`);
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/authn/info`);
|
||||
if (this.authnInfo === undefined) {
|
||||
this.authnInfo = JSON.parse(await request.get(url));
|
||||
}
|
||||
|
@ -36,8 +34,9 @@ export class AuthnClient extends OpenPAIBaseClient {
|
|||
*/
|
||||
public async oidcLogin(queryString?: string): Promise<any> {
|
||||
const url: string = 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`);
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/authn/oidc/login?${queryString}`) :
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/authn/oidc/login`);
|
||||
// tslint:disable-next-line:no-unnecessary-local-variable
|
||||
const res: string = await request.get(url);
|
||||
|
||||
return res;
|
||||
|
@ -48,8 +47,9 @@ export class AuthnClient extends OpenPAIBaseClient {
|
|||
*/
|
||||
public async oidcLogout(queryString?: string): Promise<any> {
|
||||
const url: string = 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`);
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/authn/oidc/logout?${queryString}`) :
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/authn/oidc/logout`);
|
||||
// tslint:disable-next-line:no-unnecessary-local-variable
|
||||
const res: string = await request.get(url);
|
||||
|
||||
return res;
|
|
@ -1,14 +1,11 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { ILoginInfo, IPAICluster, IPAIClusterInfo, IToken } from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
import * as request from 'request-promise-native';
|
||||
import { URL } from 'url';
|
||||
|
||||
import { Util } from '../commom/util';
|
||||
import { ILoginInfo } from '../models/authn';
|
||||
import { IPAICluster, IPAIClusterInfo } from '../models/cluster';
|
||||
import { ITokenItem } from '../models/token';
|
||||
|
||||
/**
|
||||
* OpenPAI basic client.
|
||||
*/
|
||||
|
@ -37,7 +34,7 @@ export class OpenPAIBaseClient {
|
|||
};
|
||||
protected cluster: IPAICluster;
|
||||
|
||||
private cacheToken?: ITokenItem;
|
||||
private cacheToken?: IToken;
|
||||
|
||||
constructor(cluster: IPAICluster) {
|
||||
this.cluster = OpenPAIBaseClient.parsePaiUri(cluster);
|
||||
|
@ -70,7 +67,7 @@ export class OpenPAIBaseClient {
|
|||
public async token(): Promise<string> {
|
||||
if (this.cluster.token) {
|
||||
return this.cluster.token;
|
||||
} else if (!this.cacheToken || this.cacheToken.expireTime < Date.now()) {
|
||||
} else if (!this.cacheToken || this.cacheToken.expireTime! < Date.now()) {
|
||||
const res: ILoginInfo = await this.login();
|
||||
this.cacheToken = {
|
||||
expireTime: Date.now() + 3600 * 1000,
|
||||
|
@ -84,8 +81,8 @@ export class OpenPAIBaseClient {
|
|||
* Basic login.
|
||||
*/
|
||||
public async login(): Promise<ILoginInfo> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/authn/basic/login`);
|
||||
const res: ILoginInfo = await request.post(url, {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/token`);
|
||||
return await request.post(url, {
|
||||
form: {
|
||||
expiration: 4000,
|
||||
password: this.cluster.password,
|
||||
|
@ -94,7 +91,5 @@ export class OpenPAIBaseClient {
|
|||
json: true,
|
||||
timeout: OpenPAIBaseClient.TIMEOUT
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
// tslint:disable-next-line:missing-jsdoc
|
||||
import { AuthnClient } from './authnClient';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
import { JobClient } from './jobClient';
|
||||
import { OpenPAIClient } from './openPAIClient';
|
||||
|
||||
export {
|
||||
OpenPAIClient,
|
||||
JobClient,
|
||||
AuthnClient,
|
||||
OpenPAIBaseClient
|
||||
};
|
|
@ -1,13 +1,11 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import * as yaml from 'js-yaml';
|
||||
import { IJobInfo, IJobSshInfo, IJobStatus, IPAICluster } from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
import { IJobConfig } from '@protocol/v1';
|
||||
import * as request from 'request-promise-native';
|
||||
|
||||
import { Util } from '../commom/util';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { IJobConfig, IJobConfigV1 } from '../models/jobConfig';
|
||||
import { IJobFrameworkInfo, IJobInfo, IJobSshInfo, IJobStatus } from '../models/jobStatus';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
|
@ -35,7 +33,7 @@ export class JobClient extends OpenPAIBaseClient {
|
|||
* @param jobName The job name.
|
||||
*/
|
||||
public async get(userName: string, jobName: string): Promise<IJobStatus> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/jobs/${jobName}`);
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/user/${userName}/jobs/${jobName}`);
|
||||
const res: string = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
@ -47,7 +45,7 @@ export class JobClient extends OpenPAIBaseClient {
|
|||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async delete(userName: string, jobName: string, token?: string): Promise<IJobStatus> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/jobs/${jobName}`);
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/user/${userName}/jobs/${jobName}`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
|
@ -62,25 +60,25 @@ export class JobClient extends OpenPAIBaseClient {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get job framework info, will call /api/v2/jobs/{userName}~{jobName}.
|
||||
* Get job framework info.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
public async getFrameworkInfo(userName: string, jobName: string): Promise<IJobStatus> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}`);
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/jobs/${userName}~${jobName}`);
|
||||
const res: string = await request.get(url);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job config, will call /api/v2/jobs/{userName}~{jobName}/config.
|
||||
* Get job config.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
public async getConfig(userName: string, jobName: string): Promise<IJobConfig> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}/config`);
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/jobs/${userName}/jobs/${jobName}/config`);
|
||||
const res: any = await request.get(url);
|
||||
return yaml.safeLoad(res);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,7 +89,7 @@ export class JobClient extends OpenPAIBaseClient {
|
|||
* @param token Specific an access token (optional).
|
||||
*/
|
||||
public async execute(userName: string, jobName: string, type: 'START' | 'STOP', token?: string): Promise<any> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/user/${userName}/jobs/${jobName}/executionType`);
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/user/${userName}/jobs/${jobName}/executionType`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
|
@ -109,31 +107,10 @@ export class JobClient extends OpenPAIBaseClient {
|
|||
}
|
||||
|
||||
/**
|
||||
* Submit a job, will call /api/v2/jobs.
|
||||
* Submit a job, will call /api/v1/user/{username}/jobs.
|
||||
* @param jobConfig The job config.
|
||||
*/
|
||||
public async submit(jobConfig: IJobConfig, token?: string): Promise<void> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/jobs`);
|
||||
const text: string = 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> {
|
||||
public async submit(userName: string, jobConfig: IJobConfig, token?: string): Promise<void> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v1/user/${userName}/jobs`);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { AuthnClient, JobClient } from '@api/v1/clients';
|
||||
import { IPAICluster } from '@api/v2';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Client.
|
||||
*/
|
||||
export class OpenPAIClient extends OpenPAIBaseClient {
|
||||
/**
|
||||
* OpenPAI Job Client.
|
||||
*/
|
||||
public job: JobClient;
|
||||
|
||||
/**
|
||||
* OpenPAI Authn Client.
|
||||
*/
|
||||
public authn: AuthnClient;
|
||||
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
this.job = new JobClient(cluster);
|
||||
this.authn = new AuthnClient(cluster);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IJobConfig } from '@protocol/v1';
|
||||
|
||||
import { AuthnClient, JobClient, OpenPAIBaseClient, OpenPAIClient } from './clients';
|
||||
|
||||
/**
|
||||
* Export OpenPAI RestAPI V1.
|
||||
*/
|
||||
export {
|
||||
AuthnClient,
|
||||
JobClient,
|
||||
OpenPAIClient,
|
||||
IJobConfig,
|
||||
OpenPAIBaseClient
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IPAICluster, IPAIClusterInfo } from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Api client.
|
||||
*/
|
||||
export class ApiClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenPAI cluster info.
|
||||
*/
|
||||
public async getClusterInfo(): Promise<IPAIClusterInfo> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/info`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IAuthnInfo, ILoginInfo, IPAICluster } from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Authn client.
|
||||
*/
|
||||
export class AuthnClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* User login with Azure AD.
|
||||
*/
|
||||
public async oidcLogin(queryString?: string): Promise<string> {
|
||||
return await this.oidcRequest('login', queryString);
|
||||
}
|
||||
|
||||
/**
|
||||
* User logout from Azure AD.
|
||||
*/
|
||||
public async oidcLogout(queryString?: string): Promise<string> {
|
||||
return await this.oidcRequest('logout', queryString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an access token using username and password.
|
||||
* @param username Username, set undefined to use the username in cluster setting.
|
||||
* @param password Password, set undefined to use the password in cluster setting.
|
||||
*/
|
||||
public async basicLogin(username?: string, password?: string): Promise<ILoginInfo> {
|
||||
return await this.httpClient.login(username, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke current login token.
|
||||
*/
|
||||
public async basicLogout(): Promise<string> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/authn/basic/logout`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
private async oidcRequest(req: 'login' | 'logout', queryString?: string): Promise<string> {
|
||||
const url: string = queryString ?
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/authn/oidc/${req}?${queryString}`, this.cluster.https) :
|
||||
Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/authn/oidc/${req}`, this.cluster.https);
|
||||
return await this.httpClient.get(url, {
|
||||
200: (data) => data
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { ILoginInfo, IPAICluster, IPAIClusterInfo } from '@api/v2';
|
||||
import { PAIHttpClient } from '@pai/commom/paiHttpClient';
|
||||
import { Util } from '@pai/commom/util';
|
||||
import { URL } from 'url';
|
||||
|
||||
/**
|
||||
* OpenPAI basic client.
|
||||
*/
|
||||
export class OpenPAIBaseClient {
|
||||
protected static readonly TIMEOUT: number = 60 * 1000;
|
||||
|
||||
/**
|
||||
* get cluster configuration / info
|
||||
*/
|
||||
public config: any = {
|
||||
/**
|
||||
* username from cluster config
|
||||
*/
|
||||
username: () => {
|
||||
return this.cluster.username;
|
||||
}
|
||||
};
|
||||
|
||||
protected readonly httpClient: PAIHttpClient;
|
||||
protected cluster: IPAICluster;
|
||||
|
||||
constructor(cluster: IPAICluster) {
|
||||
this.cluster = OpenPAIBaseClient.parsePaiUri(cluster);
|
||||
this.httpClient = new PAIHttpClient(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse information from pai_uri
|
||||
* refer to tests/unit_tests/baseClient.spec.ts
|
||||
*/
|
||||
public static parsePaiUri(cluster: IPAICluster): IPAICluster {
|
||||
if (cluster.pai_uri) {
|
||||
const paiUri: URL = new URL(Util.fixUrl(cluster.pai_uri!));
|
||||
if (!cluster.https) {
|
||||
cluster.https = paiUri.protocol === 'https:';
|
||||
}
|
||||
if (!cluster.rest_server_uri) {
|
||||
cluster.rest_server_uri = paiUri.host + '/rest-server';
|
||||
}
|
||||
if (!cluster.alias) {
|
||||
cluster.alias = paiUri.hostname;
|
||||
}
|
||||
}
|
||||
return cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenPAI access token.
|
||||
*/
|
||||
public async token(): Promise<string> {
|
||||
if (!this.cluster.token) {
|
||||
const info: ILoginInfo = await this.httpClient.login();
|
||||
this.cluster.token = info.token;
|
||||
}
|
||||
|
||||
return this.cluster.token;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { Identifiable } from '../commom/identifiable';
|
||||
import { Util } from '../commom/util';
|
||||
import { Identifiable } from '@pai/commom/identifiable';
|
||||
import { Util } from '@pai/commom/util';
|
||||
|
||||
/**
|
||||
* for some stable API calling (the results may not change for a long while)
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IGroup, IPAICluster, IPAIResponse, IUser } from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI group client.
|
||||
*/
|
||||
export class GroupClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all group objects in the system.
|
||||
*/
|
||||
public async getAllGroup(): Promise<IGroup[]> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/groups`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a group in the system.
|
||||
* @param group The group object { groupname, description, externalName, extension }.
|
||||
*/
|
||||
public async createGroup(group: IGroup): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/groups`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.post(url, group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a group in the system.
|
||||
* @param group The group object { groupname, description, externalName, extension }.
|
||||
*/
|
||||
public async updateGroup(group: IGroup): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/groups`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.put(url, group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a group in the system.
|
||||
* @param groupName The group name.
|
||||
*/
|
||||
public async getGroup(groupName: string): Promise<IGroup> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/groups/${groupName}`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a group in the system.
|
||||
* @param groupName The group name.
|
||||
*/
|
||||
public async deleteGroup(groupName: string): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/groups/${groupName}`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.delete(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user array of a group in the system.
|
||||
* @param groupName The group name.
|
||||
*/
|
||||
public async getGroupMembers(groupName: string): Promise<IUser[]> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/groups/${groupName}/userlist`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
// tslint:disable-next-line:missing-jsdoc
|
||||
import { ApiClient } from './apiClient';
|
||||
import { AuthnClient } from './authnClient';
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
import { CacheClient, ICacheRecord } from './cacheClient';
|
||||
import { GroupClient } from './groupClient';
|
||||
import { JobClient } from './jobClient';
|
||||
import { JobHistoryClient } from './jobHistoryClient';
|
||||
import { KubernetesClient } from './kubernetesClient';
|
||||
import { OpenPAIClient } from './openPAIClient';
|
||||
import { StorageClient } from './storageClient';
|
||||
import { UserClient } from './userClient';
|
||||
import { VirtualClusterClient } from './virtualClusterClient';
|
||||
|
||||
export {
|
||||
OpenPAIBaseClient,
|
||||
OpenPAIClient,
|
||||
JobClient,
|
||||
UserClient,
|
||||
VirtualClusterClient,
|
||||
AuthnClient,
|
||||
StorageClient,
|
||||
ICacheRecord,
|
||||
CacheClient,
|
||||
GroupClient,
|
||||
ApiClient,
|
||||
JobHistoryClient,
|
||||
KubernetesClient
|
||||
};
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import {
|
||||
IJobConfig, IJobInfo, IJobSshInfo, IJobStatus, IPAICluster, IPAIResponse
|
||||
} from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
import * as yaml from 'js-yaml';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Job client.
|
||||
*/
|
||||
export class JobClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a job in the system.
|
||||
* @param jobConfig The job config.
|
||||
*/
|
||||
public async createJob(jobConfig: IJobConfig): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/jobs`,
|
||||
this.cluster.https
|
||||
);
|
||||
const text: string = yaml.safeDump(jobConfig);
|
||||
|
||||
return await this.httpClient.post(url, text, undefined, {
|
||||
headers: {
|
||||
'Content-Type': 'text/yaml'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of jobs.
|
||||
* @param username filter jobs with username.
|
||||
*/
|
||||
public async listJobs(username?: string): Promise<IJobInfo[]> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/jobs`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(
|
||||
url, undefined, undefined, { username }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job status.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
public async getJob(userName: string, jobName: string): Promise<IJobStatus> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job configuration.
|
||||
* This API always returns job config in v2 format (text/yaml).
|
||||
* Old job config in v1 format will be converted automatically.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
public async getJobConfig(userName: string, jobName: string): Promise<IJobConfig> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}/config`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url, {
|
||||
200: (data) => yaml.safeLoad(data)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start or stop a job.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
* @param type 'START' or 'STOP'.
|
||||
*/
|
||||
public async updateJobExecutionType(userName: string, jobName: string, type: 'START' | 'STOP'): Promise<any> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}/executionType`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.put(url, { value: type });
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import {
|
||||
IJobAttempt, IPAICluster, IPAIResponse
|
||||
} from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Job client.
|
||||
*/
|
||||
export class JobHistoryClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if job attempts is healthy.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
public async getJobAttemptsHealthz(userName: string, jobName: string): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}/job-attempts/healthz`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all attempts of a job.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
*/
|
||||
public async getJobAttempts(userName: string, jobName: string): Promise<IJobAttempt[]> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}/job-attempts`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific attempt by attempt index.
|
||||
* @param userName The user name.
|
||||
* @param jobName The job name.
|
||||
* @param index The job attempt index.
|
||||
*/
|
||||
public async getJobAttempt(
|
||||
userName: string, jobName: string, index: number
|
||||
): Promise<IJobAttempt> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/jobs/${userName}~${jobName}/job-attempts/${index}`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import {
|
||||
IJobAttempt, IPAICluster, IPAIResponse
|
||||
} from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Kubernetes client.
|
||||
*/
|
||||
export class KubernetesClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get kubernetes node list. Need administrator permission.
|
||||
*/
|
||||
public async getK8sNodes(): Promise<any> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/kubernetes/nodes`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get kubernetes pod list.
|
||||
*/
|
||||
public async getK8sPods(): Promise<any> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/kubernetes/pods`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,21 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { AuthnClient } from '..';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
import { CacheClient, ICacheRecord } from './cacheClient';
|
||||
import { JobClient } from './jobClient';
|
||||
import { StorageClient } from './storageClient';
|
||||
import { UserClient } from './userClient';
|
||||
import { VirtualClusterClient } from './virtualClusterClient';
|
||||
import { IPAICluster } from '@api/v2';
|
||||
import {
|
||||
ApiClient,
|
||||
AuthnClient,
|
||||
CacheClient,
|
||||
GroupClient,
|
||||
ICacheRecord,
|
||||
JobClient,
|
||||
JobHistoryClient,
|
||||
KubernetesClient,
|
||||
OpenPAIBaseClient,
|
||||
StorageClient,
|
||||
UserClient,
|
||||
VirtualClusterClient
|
||||
} from '@api/v2/clients';
|
||||
|
||||
/**
|
||||
* OpenPAI Client.
|
||||
|
@ -45,6 +51,26 @@ export class OpenPAIClient extends OpenPAIBaseClient {
|
|||
*/
|
||||
public cache: CacheClient;
|
||||
|
||||
/**
|
||||
* OpenPAI Group Client.
|
||||
*/
|
||||
public group: GroupClient;
|
||||
|
||||
/**
|
||||
* OpenPAI API info Client.
|
||||
*/
|
||||
public api: ApiClient;
|
||||
|
||||
/**
|
||||
* OpenPAI job history Client.
|
||||
*/
|
||||
public jobHistory: JobHistoryClient;
|
||||
|
||||
/**
|
||||
* OpenPAI kubernetes Client.
|
||||
*/
|
||||
public kubernetes: KubernetesClient;
|
||||
|
||||
constructor(cluster: IPAICluster, cache?: ICacheRecord[]) {
|
||||
super(cluster);
|
||||
this.job = new JobClient(cluster);
|
||||
|
@ -52,9 +78,13 @@ export class OpenPAIClient extends OpenPAIBaseClient {
|
|||
this.virtualCluster = new VirtualClusterClient(cluster);
|
||||
this.authn = new AuthnClient(cluster);
|
||||
this.storage = new StorageClient(cluster);
|
||||
this.group = new GroupClient(cluster);
|
||||
this.api = new ApiClient(cluster);
|
||||
this.jobHistory = new JobHistoryClient(cluster);
|
||||
this.kubernetes = new KubernetesClient(cluster);
|
||||
|
||||
this.cache = new CacheClient(cache);
|
||||
this.cache.delegate(this.storage, this.storage.getStorages);
|
||||
this.cache.delegate(this.storage, this.storage.getStorageByName);
|
||||
this.cache.delegate(this.storage, this.storage.getStorage);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IPAICluster } from '@api/v2';
|
||||
import { IStorageDetail, IStorageSummary } from '@api/v2/models/storage';
|
||||
import { Util } from '@pai/commom/util';
|
||||
import { IAzureBlobCfg } from '@pai/storage/clients/azureBlobClient';
|
||||
import { IStorageDispatcher, StorageNode } from '@pai/storage/clients/storageNode';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Job client.
|
||||
*/
|
||||
export class StorageClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get storage list for which current user has permissions.
|
||||
*/
|
||||
public async getStorages(): Promise<IStorageSummary> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/storages`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get storage for the given name.
|
||||
* @param name The name of storage.
|
||||
*/
|
||||
public async getStorage(name: string): Promise<IStorageDetail> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/storages/${name}`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* StorageNode accepting v2 storage detail
|
||||
*/
|
||||
export class StorageNodeV2 extends StorageNode<IStorageDetail> {
|
||||
public storageConfigDispatcher(config: IStorageDetail): IStorageDispatcher {
|
||||
if (config.type === 'azureBlob') {
|
||||
return {
|
||||
type: config.type,
|
||||
data: config.data as IAzureBlobCfg
|
||||
};
|
||||
}
|
||||
throw Error('NotImplemented');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IPAICluster, IPAIResponse, IToken, ITokenList } from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Api client.
|
||||
*/
|
||||
export class TokenClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get your currently signed tokens.
|
||||
*/
|
||||
public async getTokens(): Promise<ITokenList> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/tokens`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a token.
|
||||
* @param deleteToken The token string.
|
||||
*/
|
||||
public async deleteToken(deleteToken: string): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/tokens/${deleteToken}`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.delete(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an application access token in the system.
|
||||
*/
|
||||
public async createApplicationToken(): Promise<IToken> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/tokens/application`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.post(url, {});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IPAICluster, IPAIResponse, IUser } from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI User client.
|
||||
*/
|
||||
export class UserClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a user in the system.
|
||||
* @param user The user info: { username, email, password, admin, virtualCluster, extension }.
|
||||
*/
|
||||
public async createUser(user: IUser): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/users/`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.post(url, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all users in the system by admin.
|
||||
*/
|
||||
public async getAllUser(): Promise<IUser[]> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/users/`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a user in the system. Admin only.
|
||||
* @param user The user info: { username, email, password, admin, virtualCluster, extension }.
|
||||
*/
|
||||
public async updateUser(user: IUser): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/users`,
|
||||
this.cluster.https
|
||||
);
|
||||
return this.httpClient.put(url, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's own profile in the system.
|
||||
* @param username The user name.
|
||||
* @param email The new email address, optional.
|
||||
* @param newPassword The new password, optional.
|
||||
* @param oldPassword The old password, optional.
|
||||
*/
|
||||
public async updateUserSelf(
|
||||
username: string, email?: string, newPassword?: string, oldPassword?: string
|
||||
): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/users/me`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.put(url, { username, email, newPassword, oldPassword });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user's data.
|
||||
* @param userName The user's name.
|
||||
*/
|
||||
public async getUser(userName: string): Promise<IUser> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/users/${userName}`,
|
||||
this.cluster.https
|
||||
);
|
||||
return this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user in the system.
|
||||
* Basic mode only.
|
||||
* Admin only.
|
||||
* @param userName The user's name.
|
||||
*/
|
||||
public async deleteUser(userName: string): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/users/${userName}`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.delete(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a group to a user's grouplist.
|
||||
* Basic mode only.
|
||||
* Admin only.
|
||||
* @param userName The user name.
|
||||
* @param groupname The new groupname in [A-Za-z0-9_]+ format.
|
||||
*/
|
||||
public async updateUserGroup(userName: string, groupname: string): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/users/${userName}/group`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.put(url, { groupname });
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a group from user's grouplist.
|
||||
* Basic mode only.
|
||||
* Admin only.
|
||||
* @param userName The user name.
|
||||
* @param groupname The groupname in [A-Za-z0-9_]+ format.
|
||||
*/
|
||||
public async deleteUserGroup(userName: string, groupname: string): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/users/${userName}/group`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.delete(url, undefined, { data: { groupname } });
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a user's grouplist.
|
||||
* Basic mode only.
|
||||
* Admin only.
|
||||
* @param userName The user name.
|
||||
* @param grouplist The new group list.
|
||||
*/
|
||||
public async updateUserGrouplist(userName: string, grouplist: string[]): Promise<IPAIResponse> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/users/${userName}/grouplist`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.put(url, { grouplist });
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IPAICluster, IVirtualCluster } from '@api/v2';
|
||||
import { Util } from '@pai/commom/util';
|
||||
|
||||
import { ISkuType } from '../models/virtualCluster';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* OpenPAI Virtual Cluster client.
|
||||
*/
|
||||
export class VirtualClusterClient extends OpenPAIBaseClient {
|
||||
constructor(cluster: IPAICluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of virtual clusters.
|
||||
*/
|
||||
public async listVirtualClusters(): Promise<{ [id: string]: IVirtualCluster; }> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/virtual-clusters`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get virtual cluster status in the system.
|
||||
* @param vcName The name of virtual cluster.
|
||||
*/
|
||||
public async getVirtualCluster(vcName: string): Promise<IVirtualCluster> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/virtual-clusters/${vcName}`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sku types in the virtual cluster.
|
||||
* @param vcName The name of virtual cluster.
|
||||
*/
|
||||
public async getVirtualClusterSkuTypes(vcName: string): Promise<{ [id: string]: ISkuType; }> {
|
||||
const url: string = Util.fixUrl(
|
||||
`${this.cluster.rest_server_uri}/api/v2/virtual-clusters/${vcName}/sku-types`,
|
||||
this.cluster.https
|
||||
);
|
||||
return await this.httpClient.get(url);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IJobConfig } from '@protocol/v2';
|
||||
|
||||
import {
|
||||
ApiClient,
|
||||
AuthnClient,
|
||||
JobClient,
|
||||
JobHistoryClient,
|
||||
OpenPAIBaseClient,
|
||||
OpenPAIClient,
|
||||
StorageClient,
|
||||
UserClient,
|
||||
VirtualClusterClient
|
||||
} from './clients';
|
||||
import { GroupClient } from './clients/groupClient';
|
||||
import { StorageNodeV2 as StorageNode } from './clients/storageClient';
|
||||
import { IAuthnInfo, ILoginInfo } from './models/authn';
|
||||
import { IPAICluster, IPAIClusterInfo } from './models/cluster';
|
||||
import { IGroup } from './models/group';
|
||||
import { IJobAttempt, IJobFrameworkInfo, IJobInfo, IJobSshInfo, IJobStatus } from './models/job';
|
||||
import { IPAIResponse } from './models/paiResponse';
|
||||
import { IMountInfo, IStorageConfig, IStorageDetail, IStorageServer, IStorageSummary } from './models/storage';
|
||||
import { IToken, ITokenList } from './models/token';
|
||||
import { IUser } from './models/user';
|
||||
import { INodeResource, IVirtualCluster } from './models/virtualCluster';
|
||||
|
||||
/**
|
||||
* Export OpenPAI RestAPI V1.
|
||||
*/
|
||||
export {
|
||||
AuthnClient,
|
||||
JobClient,
|
||||
OpenPAIClient,
|
||||
OpenPAIBaseClient,
|
||||
StorageClient,
|
||||
UserClient,
|
||||
VirtualClusterClient,
|
||||
IPAICluster,
|
||||
IPAIClusterInfo,
|
||||
IJobConfig,
|
||||
IJobInfo,
|
||||
IJobFrameworkInfo,
|
||||
IJobSshInfo,
|
||||
IJobAttempt,
|
||||
IUser,
|
||||
IToken,
|
||||
ITokenList,
|
||||
IVirtualCluster,
|
||||
INodeResource,
|
||||
IAuthnInfo,
|
||||
ILoginInfo,
|
||||
IStorageServer,
|
||||
IStorageConfig,
|
||||
IStorageSummary,
|
||||
IStorageDetail,
|
||||
IMountInfo,
|
||||
IJobStatus,
|
||||
StorageNode,
|
||||
IGroup,
|
||||
GroupClient,
|
||||
ApiClient,
|
||||
JobHistoryClient,
|
||||
IPAIResponse
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/**
|
||||
* OpenPAI group.
|
||||
*/
|
||||
export interface IGroup {
|
||||
groupname: string;
|
||||
description?: string;
|
||||
externalName?: string;
|
||||
extension?: object;
|
||||
}
|
|
@ -123,3 +123,83 @@ export interface IJobSshInfo {
|
|||
containers?: any | null;
|
||||
keyPair?: any | null;
|
||||
}
|
||||
|
||||
export interface IJobAttempt {
|
||||
jobName?: string;
|
||||
frameworkName?: string;
|
||||
uid?: string;
|
||||
userName?: string;
|
||||
state?: string;
|
||||
originState?: string;
|
||||
maxAttemptCount?: number;
|
||||
attemptIndex?: number;
|
||||
jobStartedTime?: number;
|
||||
attemptStartedTime?: number;
|
||||
attemptCompletedTime?: number;
|
||||
exitCode?: number;
|
||||
exitPhrase?: string;
|
||||
exitType?: string;
|
||||
exitDiagnostics?: {
|
||||
diagnosticsSummary?: string;
|
||||
runtime?: {
|
||||
exitCode?: number;
|
||||
originUserExitCode?: number;
|
||||
errorLogs?: {
|
||||
user?: string;
|
||||
platform?: string;
|
||||
};
|
||||
name?: string;
|
||||
};
|
||||
launcher?: string;
|
||||
};
|
||||
appExitTriggerMessage?: string;
|
||||
appExitTriggerTaskRoleName?: string;
|
||||
appExitTriggerTaskIndex?: number;
|
||||
appExitSpec: {
|
||||
code?: number;
|
||||
phrase?: string;
|
||||
issuer?: string;
|
||||
causer?: string;
|
||||
type?: string;
|
||||
stage?: string;
|
||||
behavior?: string;
|
||||
reaction?: string;
|
||||
reason?: string;
|
||||
repro?: string[];
|
||||
solution?: string[];
|
||||
};
|
||||
appExitDiagnostics?: string;
|
||||
appExitMessages?: {
|
||||
container?: string;
|
||||
runtime?: {
|
||||
exitCode?: number;
|
||||
originUserExitCode?: number;
|
||||
errorLogs?: {
|
||||
user?: string;
|
||||
platform?: string;
|
||||
};
|
||||
name?: string;
|
||||
};
|
||||
launcher?: string;
|
||||
};
|
||||
totalGpuNumber?: number;
|
||||
totalTasknumber?: number;
|
||||
totalTaskRoleNumber?: number;
|
||||
taskRoles?: {
|
||||
taskrole?: {
|
||||
taskRoleStatus: {
|
||||
name?: string;
|
||||
};
|
||||
taskStatuses?: {
|
||||
taskIndex?: number;
|
||||
taskState?: string;
|
||||
containerId?: string;
|
||||
containerIp?: string;
|
||||
containerGpus?: string;
|
||||
containerLog?: string;
|
||||
containerExitCode?: number;
|
||||
}[];
|
||||
};
|
||||
};
|
||||
isLatest?: boolean;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/**
|
||||
* OpenPAI Response.
|
||||
*/
|
||||
export interface IPAIResponse {
|
||||
code?: string;
|
||||
message?: string;
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IAzureBlobCfg } from '@pai/storage/clients/azureBlobClient';
|
||||
|
||||
/**
|
||||
* OpenPAI storage information.
|
||||
*/
|
||||
|
@ -55,13 +57,6 @@ export interface IAzureFileCfg {
|
|||
accountKey?: string;
|
||||
}
|
||||
|
||||
export interface IAzureBlobCfg {
|
||||
containerName: string;
|
||||
accountName?: string;
|
||||
accountKey?: string;
|
||||
accountSASToken?: string;
|
||||
}
|
||||
|
||||
export interface IStorageDetail extends IStorageSummaryItem {
|
||||
type: 'nfs' | 'samba' | 'azureFile' | 'azureBlob' | 'other' | 'unknown';
|
||||
data: INfsCfg | ISambaCfg | IAzureBlobCfg | IAzureFileCfg | Object;
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/**
|
||||
* OpenPAI access token.
|
||||
*/
|
||||
export interface IToken {
|
||||
token: string;
|
||||
expireTime?: number;
|
||||
application?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenPAI token list.
|
||||
*/
|
||||
export interface ITokenList {
|
||||
tokens?: string[];
|
||||
}
|
|
@ -4,11 +4,13 @@
|
|||
/**
|
||||
* OpenPAI User Info.
|
||||
*/
|
||||
export interface IUserInfo {
|
||||
export interface IUser {
|
||||
username?: string | null;
|
||||
password?: string | null;
|
||||
grouplist?: string[] | null;
|
||||
email?: string | null;
|
||||
extension?: any | null;
|
||||
admin?: boolean;
|
||||
virtualCluster?: string[] | null;
|
||||
storageConfig?: any | null;
|
||||
}
|
|
@ -47,3 +47,12 @@ export interface INodeResource {
|
|||
gpuUsed: number;
|
||||
gpuAvaiable: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenPAI SKU type.
|
||||
*/
|
||||
export interface ISkuType {
|
||||
cpu?: number;
|
||||
memory?: number;
|
||||
gpu?: number;
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
// tslint:disable-next-line:match-default-export-name
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
|
||||
import { Util } from '../commom/util';
|
||||
import { IPAICluster } from '../models/cluster';
|
||||
import { IStorageConfig, IStorageDetail, IStorageServer, IStorageSummary } from '../models/storage';
|
||||
|
||||
import { OpenPAIBaseClient } from './baseClient';
|
||||
|
||||
/**
|
||||
* 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: string = names ? `?names=${names}` : '';
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/server${query}`, this.cluster.https);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res: AxiosResponse<IStorageServer[]> = 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: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/server/${storage}`, this.cluster.https);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res: AxiosResponse<IStorageServer> = 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: string = names ? `?names=${names}` : '';
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/config${query}`, this.cluster.https);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res: AxiosResponse<IStorageConfig[]> = 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: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storage/config/${storage}`, this.cluster.https);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res: AxiosResponse<IStorageConfig> = await axios.get<IStorageConfig>(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
|
||||
public async getStorages(token?: string): Promise<IStorageSummary> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storages`, this.cluster.https);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res: AxiosResponse<IStorageSummary> = await axios.get<IStorageSummary>(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
|
||||
public async getStorageByName(name: string, token?: string): Promise<IStorageDetail> {
|
||||
const url: string = Util.fixUrl(`${this.cluster.rest_server_uri}/api/v2/storages/${name}`, this.cluster.https);
|
||||
if (token === undefined) {
|
||||
token = await super.token();
|
||||
}
|
||||
const res: AxiosResponse<IStorageDetail> = await axios.get<IStorageDetail>(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче