mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 11:01:37 -05:00
Fix HDFS AD write support + improve error logging (#6855)
* Fix HDFS AD write support + improve error logging - Implemented write stream piping correctly so data is paused until we're ready to push to server - During testing, noted that things weren't awaited correctly. Tweaked some functions to improve this * Use correct content type
This commit is contained in:
@@ -84,7 +84,7 @@ export class UploadFilesCommand extends ProgressCommand {
|
|||||||
if (fileUris) {
|
if (fileUris) {
|
||||||
let files: IFile[] = fileUris.map(uri => uri.fsPath).map(this.mapPathsToFiles());
|
let files: IFile[] = fileUris.map(uri => uri.fsPath).map(this.mapPathsToFiles());
|
||||||
await this.executeWithProgress(
|
await this.executeWithProgress(
|
||||||
async (cancelToken: vscode.CancellationTokenSource) => this.writeFiles(files, folderNode, cancelToken),
|
(cancelToken: vscode.CancellationTokenSource) => this.writeFiles(files, folderNode, cancelToken),
|
||||||
localize('uploading', 'Uploading files to HDFS'), true,
|
localize('uploading', 'Uploading files to HDFS'), true,
|
||||||
() => this.apiWrapper.showInformationMessage(localize('uploadCanceled', 'Upload operation was canceled')));
|
() => this.apiWrapper.showInformationMessage(localize('uploadCanceled', 'Upload operation was canceled')));
|
||||||
if (context.type === constants.ObjectExplorerService) {
|
if (context.type === constants.ObjectExplorerService) {
|
||||||
@@ -264,7 +264,7 @@ export class SaveFileCommand extends ProgressCommand {
|
|||||||
});
|
});
|
||||||
if (fileUri) {
|
if (fileUri) {
|
||||||
await this.executeWithProgress(
|
await this.executeWithProgress(
|
||||||
async (cancelToken: vscode.CancellationTokenSource) => this.doSaveAndOpen(fileUri, fileNode, cancelToken),
|
(cancelToken: vscode.CancellationTokenSource) => this.doSaveAndOpen(fileUri, fileNode, cancelToken),
|
||||||
localize('saving', 'Saving HDFS Files'), true,
|
localize('saving', 'Saving HDFS Files'), true,
|
||||||
() => this.apiWrapper.showInformationMessage(localize('saveCanceled', 'Save operation was canceled')));
|
() => this.apiWrapper.showInformationMessage(localize('saveCanceled', 'Save operation was canceled')));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,16 @@ import { IHdfsOptions, IRequestParams } from './fileSources';
|
|||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
const ErrorMessageInvalidDataStructure = localize('webhdfs.invalidDataStructure', "Invalid Data Structure");
|
const ErrorMessageInvalidDataStructure = localize('webhdfs.invalidDataStructure', "Invalid Data Structure");
|
||||||
|
|
||||||
|
const emitError = (instance, err) => {
|
||||||
|
const isErrorEmitted = instance.errorEmitted;
|
||||||
|
|
||||||
|
if (!isErrorEmitted) {
|
||||||
|
instance.emit('error', err);
|
||||||
|
instance.emit('finish');
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.errorEmitted = true;
|
||||||
|
};
|
||||||
export class WebHDFS {
|
export class WebHDFS {
|
||||||
private _requestParams: IRequestParams;
|
private _requestParams: IRequestParams;
|
||||||
private _opts: IHdfsOptions;
|
private _opts: IHdfsOptions;
|
||||||
@@ -544,31 +554,55 @@ export class WebHDFS {
|
|||||||
return this.doCreateWriteStream(params);
|
return this.doCreateWriteStream(params);
|
||||||
}
|
}
|
||||||
// Else, must add kerberos token and handle redirects
|
// Else, must add kerberos token and handle redirects
|
||||||
|
return this.createKerberosWriteStream(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createKerberosWriteStream(params: any): fs.WriteStream {
|
||||||
params.followRedirect = false;
|
params.followRedirect = false;
|
||||||
let replyStream = through();
|
// Create an intermediate stream that pauses until we get a positive
|
||||||
|
// response from the server
|
||||||
|
let isWaiting = true;
|
||||||
|
let firstCb: Function = undefined;
|
||||||
|
let replyStream = through(function (chunk, enc, cb) {
|
||||||
|
this.push(chunk, enc);
|
||||||
|
if (isWaiting) {
|
||||||
|
firstCb = cb;
|
||||||
|
} else {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
let handleErr = (err) => {
|
let handleErr = (err) => {
|
||||||
replyStream.emit('error', err);
|
replyStream.emit('error', err);
|
||||||
replyStream.end();
|
replyStream.end();
|
||||||
};
|
};
|
||||||
let initRedirectedStream = () => {
|
let initRedirectedStream = () => {
|
||||||
let redirectedStream = this.doCreateWriteStream(params);
|
// After redirect, create valid stream to correct location
|
||||||
replyStream.pipe(redirectedStream);
|
// and pipe the intermediate stream to it, unblocking the data flow
|
||||||
|
params.headers['content-type'] = 'application/octet-stream';
|
||||||
|
let upload = request(params, (err, res, bo) => {
|
||||||
|
if (err || this.isError(res)) {
|
||||||
|
emitError(replyStream, this.parseError(res, bo, err));
|
||||||
|
replyStream.end();
|
||||||
|
}
|
||||||
|
else if (res.headers.hasOwnProperty('location')) {
|
||||||
|
replyStream.emit('finish', res.headers.location);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
replyStream.emit('finish');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
isWaiting = false;
|
||||||
|
replyStream.pipe(upload);
|
||||||
|
if (firstCb) {
|
||||||
|
firstCb();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
this.requestWithRedirectAndAuth(params, initRedirectedStream, handleErr);
|
this.requestWithRedirectAndAuth(params, initRedirectedStream, handleErr);
|
||||||
return <fs.WriteStream><any>replyStream;
|
return <fs.WriteStream><any>replyStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private doCreateWriteStream(params: any): fs.WriteStream {
|
private doCreateWriteStream(params: any): fs.WriteStream {
|
||||||
let emitError = (instance, err) => {
|
|
||||||
const isErrorEmitted = instance.errorEmitted;
|
|
||||||
|
|
||||||
if (!isErrorEmitted) {
|
|
||||||
instance.emit('error', err);
|
|
||||||
instance.emit('finish');
|
|
||||||
}
|
|
||||||
|
|
||||||
instance.errorEmitted = true;
|
|
||||||
};
|
|
||||||
let canResume: boolean = true;
|
let canResume: boolean = true;
|
||||||
let stream = undefined;
|
let stream = undefined;
|
||||||
let req = request(params, (error, response, body) => {
|
let req = request(params, (error, response, body) => {
|
||||||
@@ -680,6 +714,8 @@ export class WebHDFS {
|
|||||||
this.setKerberosAuthOnParams(params)
|
this.setKerberosAuthOnParams(params)
|
||||||
.then(onRedirected)
|
.then(onRedirected)
|
||||||
.catch(handleErr);
|
.catch(handleErr);
|
||||||
|
} else {
|
||||||
|
handleErr(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user