Unverified Commit 1328f412 authored by chicm-ms's avatar chicm-ms Committed by GitHub
Browse files

Fix eslint errors (#1836)

* update eslint rules
* auto fix eslint
* manually fix eslint (#1833)
parent 8c07cf41
...@@ -4,12 +4,10 @@ ...@@ -4,12 +4,10 @@
'use strict'; 'use strict';
import * as assert from 'assert'; import * as assert from 'assert';
import * as cpp from 'child-process-promise';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import * as fs from 'fs'; import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import { Client, ConnectConfig } from 'ssh2'; import { Client } from 'ssh2';
import { Deferred } from 'ts-deferred'; import { Deferred } from 'ts-deferred';
import { String } from 'typescript-string-operations'; import { String } from 'typescript-string-operations';
import * as component from '../../common/component'; import * as component from '../../common/component';
...@@ -29,12 +27,12 @@ import { CONTAINER_INSTALL_NNI_SHELL_FORMAT } from '../common/containerJobData'; ...@@ -29,12 +27,12 @@ import { CONTAINER_INSTALL_NNI_SHELL_FORMAT } from '../common/containerJobData';
import { GPUSummary } from '../common/gpuData'; import { GPUSummary } from '../common/gpuData';
import { TrialConfig } from '../common/trialConfig'; import { TrialConfig } from '../common/trialConfig';
import { TrialConfigMetadataKey } from '../common/trialConfigMetadataKey'; import { TrialConfigMetadataKey } from '../common/trialConfigMetadataKey';
import { execCopydir, execMkdir, execRemove, validateCodeDir, getGpuMetricsCollectorBashScriptContent } from '../common/util'; import { execCopydir, execMkdir, validateCodeDir, getGpuMetricsCollectorBashScriptContent } from '../common/util';
import { GPUScheduler } from './gpuScheduler'; import { GPUScheduler } from './gpuScheduler';
import { import {
HOST_JOB_SHELL_FORMAT, RemoteCommandResult, REMOTEMACHINE_TRIAL_COMMAND_FORMAT, RemoteMachineMeta, RemoteCommandResult, REMOTEMACHINE_TRIAL_COMMAND_FORMAT, RemoteMachineMeta,
RemoteMachineScheduleInfo, RemoteMachineScheduleResult, RemoteMachineTrialJobDetail, RemoteMachineScheduleInfo, RemoteMachineScheduleResult, RemoteMachineTrialJobDetail,
ScheduleResultType, SSHClient, SSHClientManager ScheduleResultType, SSHClientManager
} from './remoteMachineData'; } from './remoteMachineData';
import { RemoteMachineJobRestServer } from './remoteMachineJobRestServer'; import { RemoteMachineJobRestServer } from './remoteMachineJobRestServer';
import { SSHClientUtility } from './sshClientUtility'; import { SSHClientUtility } from './sshClientUtility';
...@@ -93,7 +91,7 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -93,7 +91,7 @@ class RemoteMachineTrainingService implements TrainingService {
while (this.jobQueue.length > 0) { while (this.jobQueue.length > 0) {
this.updateGpuReservation(); this.updateGpuReservation();
const trialJobId: string = this.jobQueue[0]; const trialJobId: string = this.jobQueue[0];
const prepareResult : boolean = await this.prepareTrialJob(trialJobId); const prepareResult: boolean = await this.prepareTrialJob(trialJobId);
if (prepareResult) { if (prepareResult) {
// Remove trial job with trialJobId from job queue // Remove trial job with trialJobId from job queue
this.jobQueue.shift(); this.jobQueue.shift();
...@@ -241,12 +239,7 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -241,12 +239,7 @@ class RemoteMachineTrainingService implements TrainingService {
if (trialJobDetail === undefined) { if (trialJobDetail === undefined) {
throw new Error(`updateTrialJob failed: ${trialJobId} not found`); throw new Error(`updateTrialJob failed: ${trialJobId} not found`);
} }
const rmMeta: RemoteMachineMeta | undefined = (<RemoteMachineTrialJobDetail>trialJobDetail).rmMeta; await this.writeParameterFile(trialJobId, form.hyperParameters);
if (rmMeta !== undefined) {
await this.writeParameterFile(trialJobId, form.hyperParameters, rmMeta);
} else {
throw new Error(`updateTrialJob failed: ${trialJobId} rmMeta not found`);
}
return trialJobDetail; return trialJobDetail;
} }
...@@ -272,7 +265,7 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -272,7 +265,7 @@ class RemoteMachineTrainingService implements TrainingService {
} }
// Remove the job with trialJobId from job queue // Remove the job with trialJobId from job queue
const index : number = this.jobQueue.indexOf(trialJobId); const index: number = this.jobQueue.indexOf(trialJobId);
if (index >= 0) { if (index >= 0) {
this.jobQueue.splice(index, 1); this.jobQueue.splice(index, 1);
} }
...@@ -319,7 +312,7 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -319,7 +312,7 @@ class RemoteMachineTrainingService implements TrainingService {
await this.setupConnections(value); await this.setupConnections(value);
this.gpuScheduler = new GPUScheduler(this.machineSSHClientMap); this.gpuScheduler = new GPUScheduler(this.machineSSHClientMap);
break; break;
case TrialConfigMetadataKey.TRIAL_CONFIG: case TrialConfigMetadataKey.TRIAL_CONFIG: {
const remoteMachineTrailConfig: TrialConfig = <TrialConfig>JSON.parse(value); const remoteMachineTrailConfig: TrialConfig = <TrialConfig>JSON.parse(value);
// Parse trial config failed, throw Error // Parse trial config failed, throw Error
if (remoteMachineTrailConfig === undefined) { if (remoteMachineTrailConfig === undefined) {
...@@ -343,6 +336,7 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -343,6 +336,7 @@ class RemoteMachineTrainingService implements TrainingService {
this.trialConfig = remoteMachineTrailConfig; this.trialConfig = remoteMachineTrailConfig;
break; break;
}
case TrialConfigMetadataKey.MULTI_PHASE: case TrialConfigMetadataKey.MULTI_PHASE:
this.isMultiPhase = (value === 'true' || value === 'True'); this.isMultiPhase = (value === 'true' || value === 'True');
break; break;
...@@ -464,7 +458,7 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -464,7 +458,7 @@ class RemoteMachineTrainingService implements TrainingService {
} }
private async prepareTrialJob(trialJobId: string): Promise<boolean> { private async prepareTrialJob(trialJobId: string): Promise<boolean> {
const deferred : Deferred<boolean> = new Deferred<boolean>(); const deferred: Deferred<boolean> = new Deferred<boolean>();
if (this.trialConfig === undefined) { if (this.trialConfig === undefined) {
throw new Error('trial config is not initialized'); throw new Error('trial config is not initialized');
...@@ -485,13 +479,13 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -485,13 +479,13 @@ class RemoteMachineTrainingService implements TrainingService {
// get an ssh client from scheduler // get an ssh client from scheduler
const rmScheduleResult: RemoteMachineScheduleResult = this.gpuScheduler.scheduleMachine(this.trialConfig.gpuNum, trialJobDetail); const rmScheduleResult: RemoteMachineScheduleResult = this.gpuScheduler.scheduleMachine(this.trialConfig.gpuNum, trialJobDetail);
if (rmScheduleResult.resultType === ScheduleResultType.REQUIRE_EXCEED_TOTAL) { if (rmScheduleResult.resultType === ScheduleResultType.REQUIRE_EXCEED_TOTAL) {
const errorMessage : string = `Required GPU number ${this.trialConfig.gpuNum} is too large, no machine can meet`; const errorMessage: string = `Required GPU number ${this.trialConfig.gpuNum} is too large, no machine can meet`;
this.log.error(errorMessage); this.log.error(errorMessage);
deferred.reject(); deferred.reject();
throw new NNIError(NNIErrorNames.RESOURCE_NOT_AVAILABLE, errorMessage); throw new NNIError(NNIErrorNames.RESOURCE_NOT_AVAILABLE, errorMessage);
} else if (rmScheduleResult.resultType === ScheduleResultType.SUCCEED } else if (rmScheduleResult.resultType === ScheduleResultType.SUCCEED
&& rmScheduleResult.scheduleInfo !== undefined) { && rmScheduleResult.scheduleInfo !== undefined) {
const rmScheduleInfo : RemoteMachineScheduleInfo = rmScheduleResult.scheduleInfo; const rmScheduleInfo: RemoteMachineScheduleInfo = rmScheduleResult.scheduleInfo;
const trialWorkingFolder: string = unixPathJoin(this.remoteExpRootDir, 'trials', trialJobId); const trialWorkingFolder: string = unixPathJoin(this.remoteExpRootDir, 'trials', trialJobId);
trialJobDetail.rmMeta = rmScheduleInfo.rmMeta; trialJobDetail.rmMeta = rmScheduleInfo.rmMeta;
...@@ -521,7 +515,7 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -521,7 +515,7 @@ class RemoteMachineTrainingService implements TrainingService {
if (this.trialConfig === undefined) { if (this.trialConfig === undefined) {
throw new Error('trial config is not initialized'); throw new Error('trial config is not initialized');
} }
const cuda_visible_device: string = rmScheduleInfo.cuda_visible_device; const cudaVisibleDevice: string = rmScheduleInfo.cudaVisibleDevice;
const sshClient: Client | undefined = this.trialSSHClientMap.get(trialJobId); const sshClient: Client | undefined = this.trialSSHClientMap.get(trialJobId);
if (sshClient === undefined) { if (sshClient === undefined) {
assert(false, 'sshClient is undefined.'); assert(false, 'sshClient is undefined.');
...@@ -543,14 +537,14 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -543,14 +537,14 @@ class RemoteMachineTrainingService implements TrainingService {
// See definition in remoteMachineData.ts // See definition in remoteMachineData.ts
let command: string; let command: string;
// Set CUDA_VISIBLE_DEVICES environment variable based on cuda_visible_device // Set CUDA_VISIBLE_DEVICES environment variable based on cudaVisibleDevice
// If no valid cuda_visible_device is defined, set CUDA_VISIBLE_DEVICES to empty string to hide GPU device // If no valid cudaVisibleDevice is defined, set CUDA_VISIBLE_DEVICES to empty string to hide GPU device
// If gpuNum is undefined, will not set CUDA_VISIBLE_DEVICES in script // If gpuNum is undefined, will not set CUDA_VISIBLE_DEVICES in script
if (this.trialConfig.gpuNum === undefined) { if (this.trialConfig.gpuNum === undefined) {
command = this.trialConfig.command; command = this.trialConfig.command;
} else { } else {
if (typeof cuda_visible_device === 'string' && cuda_visible_device.length > 0) { if (typeof cudaVisibleDevice === 'string' && cudaVisibleDevice.length > 0) {
command = `CUDA_VISIBLE_DEVICES=${cuda_visible_device} ${this.trialConfig.command}`; command = `CUDA_VISIBLE_DEVICES=${cudaVisibleDevice} ${this.trialConfig.command}`;
} else { } else {
command = `CUDA_VISIBLE_DEVICES=" " ${this.trialConfig.command}`; command = `CUDA_VISIBLE_DEVICES=" " ${this.trialConfig.command}`;
} }
...@@ -584,12 +578,12 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -584,12 +578,12 @@ class RemoteMachineTrainingService implements TrainingService {
//create tmp trial working folder locally. //create tmp trial working folder locally.
await execCopydir(this.trialConfig.codeDir, trialLocalTempFolder); await execCopydir(this.trialConfig.codeDir, trialLocalTempFolder);
const installScriptContent : string = CONTAINER_INSTALL_NNI_SHELL_FORMAT; const installScriptContent: string = CONTAINER_INSTALL_NNI_SHELL_FORMAT;
// Write NNI installation file to local tmp files // Write NNI installation file to local tmp files
await fs.promises.writeFile(path.join(trialLocalTempFolder, 'install_nni.sh'), installScriptContent, { encoding: 'utf8' }); await fs.promises.writeFile(path.join(trialLocalTempFolder, 'install_nni.sh'), installScriptContent, { encoding: 'utf8' });
// Write file content ( run.sh and parameter.cfg ) to local tmp files // Write file content ( run.sh and parameter.cfg ) to local tmp files
await fs.promises.writeFile(path.join(trialLocalTempFolder, 'run.sh'), runScriptTrialContent, { encoding: 'utf8' }); await fs.promises.writeFile(path.join(trialLocalTempFolder, 'run.sh'), runScriptTrialContent, { encoding: 'utf8' });
await this.writeParameterFile(trialJobId, form.hyperParameters, rmScheduleInfo.rmMeta); await this.writeParameterFile(trialJobId, form.hyperParameters);
// Copy files in codeDir to remote working directory // Copy files in codeDir to remote working directory
await SSHClientUtility.copyDirectoryToRemote(trialLocalTempFolder, trialWorkingFolder, sshClient, this.remoteOS); await SSHClientUtility.copyDirectoryToRemote(trialLocalTempFolder, trialWorkingFolder, sshClient, this.remoteOS);
// Execute command in remote machine // Execute command in remote machine
...@@ -662,7 +656,7 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -662,7 +656,7 @@ class RemoteMachineTrainingService implements TrainingService {
return unixPathJoin(getRemoteTmpDir(this.remoteOS), 'nni', 'experiments', getExperimentId()); return unixPathJoin(getRemoteTmpDir(this.remoteOS), 'nni', 'experiments', getExperimentId());
} }
public get MetricsEmitter() : EventEmitter { public get MetricsEmitter(): EventEmitter {
return this.metricsEmitter; return this.metricsEmitter;
} }
...@@ -672,13 +666,10 @@ class RemoteMachineTrainingService implements TrainingService { ...@@ -672,13 +666,10 @@ class RemoteMachineTrainingService implements TrainingService {
throw new NNIError(NNIErrorNames.INVALID_JOB_DETAIL, `Invalid job detail information for trial job ${jobId}`); throw new NNIError(NNIErrorNames.INVALID_JOB_DETAIL, `Invalid job detail information for trial job ${jobId}`);
} }
let jobpidPath: string; return unixPathJoin(trialJobDetail.workingDirectory, '.nni', 'jobpid');
jobpidPath = unixPathJoin(trialJobDetail.workingDirectory, '.nni', 'jobpid');
return jobpidPath;
} }
private async writeParameterFile(trialJobId: string, hyperParameters: HyperParameters, rmMeta: RemoteMachineMeta): Promise<void> { private async writeParameterFile(trialJobId: string, hyperParameters: HyperParameters): Promise<void> {
const sshClient: Client | undefined = this.trialSSHClientMap.get(trialJobId); const sshClient: Client | undefined = this.trialSSHClientMap.get(trialJobId);
if (sshClient === undefined) { if (sshClient === undefined) {
throw new Error('sshClient is undefined.'); throw new Error('sshClient is undefined.');
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
'use strict'; 'use strict';
import * as assert from 'assert'; import * as assert from 'assert';
import * as cpp from 'child-process-promise';
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import { Client, ClientChannel, SFTPWrapper } from 'ssh2'; import { Client, ClientChannel, SFTPWrapper } from 'ssh2';
...@@ -22,44 +21,18 @@ import { RemoteCommandResult } from './remoteMachineData'; ...@@ -22,44 +21,18 @@ import { RemoteCommandResult } from './remoteMachineData';
* *
*/ */
export namespace SSHClientUtility { export namespace SSHClientUtility {
/**
* Copy files and directories in local directory recursively to remote directory
* @param localDirectory local diretory
* @param remoteDirectory remote directory
* @param sshClient SSH client
*/
export async function copyDirectoryToRemote(localDirectory : string, remoteDirectory : string, sshClient : Client, remoteOS: string)
: Promise<void> {
const deferred: Deferred<void> = new Deferred<void>();
const tmpTarName: string = `${uniqueString(10)}.tar.gz`;
const localTarPath: string = path.join(os.tmpdir(), tmpTarName);
const remoteTarPath: string = unixPathJoin(getRemoteTmpDir(remoteOS), tmpTarName);
// Compress files in local directory to experiment root directory
await tarAdd(localTarPath, localDirectory);
// Copy the compressed file to remoteDirectory and delete it
await copyFileToRemote(localTarPath, remoteTarPath, sshClient);
await execRemove(localTarPath);
// Decompress the remote compressed file in and delete it
await remoteExeCommand(`tar -oxzf ${remoteTarPath} -C ${remoteDirectory}`, sshClient);
await remoteExeCommand(`rm ${remoteTarPath}`, sshClient);
deferred.resolve();
return deferred.promise;
}
/** /**
* Copy local file to remote path * Copy local file to remote path
* @param localFilePath the path of local file * @param localFilePath the path of local file
* @param remoteFilePath the target path in remote machine * @param remoteFilePath the target path in remote machine
* @param sshClient SSH Client * @param sshClient SSH Client
*/ */
export function copyFileToRemote(localFilePath : string, remoteFilePath : string, sshClient : Client) : Promise<boolean> { export function copyFileToRemote(localFilePath: string, remoteFilePath: string, sshClient: Client): Promise<boolean> {
const log: Logger = getLogger(); const log: Logger = getLogger();
log.debug(`copyFileToRemote: localFilePath: ${localFilePath}, remoteFilePath: ${remoteFilePath}`); log.debug(`copyFileToRemote: localFilePath: ${localFilePath}, remoteFilePath: ${remoteFilePath}`);
assert(sshClient !== undefined); assert(sshClient !== undefined);
const deferred: Deferred<boolean> = new Deferred<boolean>(); const deferred: Deferred<boolean> = new Deferred<boolean>();
sshClient.sftp((err : Error, sftp : SFTPWrapper) => { sshClient.sftp((err: Error, sftp: SFTPWrapper) => {
if (err !== undefined && err !== null) { if (err !== undefined && err !== null) {
log.error(`copyFileToRemote: ${err.message}, ${localFilePath}, ${remoteFilePath}`); log.error(`copyFileToRemote: ${err.message}, ${localFilePath}, ${remoteFilePath}`);
deferred.reject(err); deferred.reject(err);
...@@ -67,7 +40,7 @@ export namespace SSHClientUtility { ...@@ -67,7 +40,7 @@ export namespace SSHClientUtility {
return; return;
} }
assert(sftp !== undefined); assert(sftp !== undefined);
sftp.fastPut(localFilePath, remoteFilePath, (fastPutErr : Error) => { sftp.fastPut(localFilePath, remoteFilePath, (fastPutErr: Error) => {
sftp.end(); sftp.end();
if (fastPutErr !== undefined && fastPutErr !== null) { if (fastPutErr !== undefined && fastPutErr !== null) {
deferred.reject(fastPutErr); deferred.reject(fastPutErr);
...@@ -86,15 +59,15 @@ export namespace SSHClientUtility { ...@@ -86,15 +59,15 @@ export namespace SSHClientUtility {
* @param client SSH Client * @param client SSH Client
*/ */
// tslint:disable:no-unsafe-any no-any // tslint:disable:no-unsafe-any no-any
export function remoteExeCommand(command : string, client : Client): Promise<RemoteCommandResult> { export function remoteExeCommand(command: string, client: Client): Promise<RemoteCommandResult> {
const log: Logger = getLogger(); const log: Logger = getLogger();
log.debug(`remoteExeCommand: command: [${command}]`); log.debug(`remoteExeCommand: command: [${command}]`);
const deferred : Deferred<RemoteCommandResult> = new Deferred<RemoteCommandResult>(); const deferred: Deferred<RemoteCommandResult> = new Deferred<RemoteCommandResult>();
let stdout: string = ''; let stdout: string = '';
let stderr: string = ''; let stderr: string = '';
let exitCode : number; let exitCode: number;
client.exec(command, (err : Error, channel : ClientChannel) => { client.exec(command, (err: Error, channel: ClientChannel) => {
if (err !== undefined && err !== null) { if (err !== undefined && err !== null) {
log.error(`remoteExeCommand: ${err.message}`); log.error(`remoteExeCommand: ${err.message}`);
deferred.reject(err); deferred.reject(err);
...@@ -102,14 +75,14 @@ export namespace SSHClientUtility { ...@@ -102,14 +75,14 @@ export namespace SSHClientUtility {
return; return;
} }
channel.on('data', (data : any, dataStderr : any) => { channel.on('data', (data: any, dataStderr: any) => {
if (dataStderr !== undefined && dataStderr !== null) { if (dataStderr !== undefined && dataStderr !== null) {
stderr += data.toString(); stderr += data.toString();
} else { } else {
stdout += data.toString(); stdout += data.toString();
} }
}) })
.on('exit', (code : any, signal : any) => { .on('exit', (code: any, signal: any) => {
exitCode = <number>code; exitCode = <number>code;
deferred.resolve({ deferred.resolve({
stdout : stdout, stdout : stdout,
...@@ -122,9 +95,34 @@ export namespace SSHClientUtility { ...@@ -122,9 +95,34 @@ export namespace SSHClientUtility {
return deferred.promise; return deferred.promise;
} }
/**
* Copy files and directories in local directory recursively to remote directory
* @param localDirectory local diretory
* @param remoteDirectory remote directory
* @param sshClient SSH client
*/
export async function copyDirectoryToRemote(localDirectory: string, remoteDirectory: string, sshClient: Client, remoteOS: string): Promise<void> {
const deferred: Deferred<void> = new Deferred<void>();
const tmpTarName: string = `${uniqueString(10)}.tar.gz`;
const localTarPath: string = path.join(os.tmpdir(), tmpTarName);
const remoteTarPath: string = unixPathJoin(getRemoteTmpDir(remoteOS), tmpTarName);
// Compress files in local directory to experiment root directory
await tarAdd(localTarPath, localDirectory);
// Copy the compressed file to remoteDirectory and delete it
await copyFileToRemote(localTarPath, remoteTarPath, sshClient);
await execRemove(localTarPath);
// Decompress the remote compressed file in and delete it
await remoteExeCommand(`tar -oxzf ${remoteTarPath} -C ${remoteDirectory}`, sshClient);
await remoteExeCommand(`rm ${remoteTarPath}`, sshClient);
deferred.resolve();
return deferred.promise;
}
export function getRemoteFileContent(filePath: string, sshClient: Client): Promise<string> { export function getRemoteFileContent(filePath: string, sshClient: Client): Promise<string> {
const deferred: Deferred<string> = new Deferred<string>(); const deferred: Deferred<string> = new Deferred<string>();
sshClient.sftp((err: Error, sftp : SFTPWrapper) => { sshClient.sftp((err: Error, sftp: SFTPWrapper) => {
if (err !== undefined && err !== null) { if (err !== undefined && err !== null) {
getLogger() getLogger()
.error(`getRemoteFileContent: ${err.message}`); .error(`getRemoteFileContent: ${err.message}`);
...@@ -133,10 +131,10 @@ export namespace SSHClientUtility { ...@@ -133,10 +131,10 @@ export namespace SSHClientUtility {
return; return;
} }
try { try {
const sftpStream : stream.Readable = sftp.createReadStream(filePath); const sftpStream: stream.Readable = sftp.createReadStream(filePath);
let dataBuffer: string = ''; let dataBuffer: string = '';
sftpStream.on('data', (data : Buffer | string) => { sftpStream.on('data', (data: Buffer | string) => {
dataBuffer += data; dataBuffer += data;
}) })
.on('error', (streamErr: Error) => { .on('error', (streamErr: Error) => {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment