More HDFS Manage Access dialog updates (#7692)

* Add support for default permissions on directories

(cherry picked from commit 4e81cceba142c6763c3447b4d2965cd75764f8f9)

* Remove unneeded import

(cherry picked from commit ffe5f357357e75e9290966e89768c699df2e1311)

* Add recursive apply and clean up webhdfs

(cherry picked from commit ae76df14f99e599df1cdfcc74ee22d3822f11a59)

* Final set of changes

* Undo changes to azdata/sqlops and few minor fixes

* Remove cast to fix build error

* Hide defaults checkbox for files and switch checkbox order
This commit is contained in:
Charles Gagnon
2019-10-11 15:18:17 -07:00
committed by GitHub
parent 888327f5bc
commit d02c680dab
9 changed files with 466 additions and 162 deletions

View File

@@ -11,9 +11,9 @@ import * as through from 'through2';
import * as nls from 'vscode-nls';
import * as auth from '../util/auth';
import { IHdfsOptions, IRequestParams } from '../objectExplorerNodeProvider/fileSources';
import { PermissionStatus, AclEntry, parseAcl, PermissionType, parseAclPermissionFromOctal, AclEntryScope } from './aclEntry';
import { PermissionStatus, AclEntry, parseAclList, PermissionType, parseAclPermissionFromOctal, AclEntryScope, AclType } from './aclEntry';
import { Mount } from './mount';
import { everyoneName } from '../localizedConstants';
import { everyoneName, ownerPostfix, owningGroupPostfix } from '../localizedConstants';
import { FileStatus, parseHdfsFileType } from './fileStatus';
const localize = nls.loadMessageBundle();
@@ -340,11 +340,11 @@ export class WebHDFS {
}
/**
* Read directory contents
* List the status of a path
*
* @returns void
*/
public readdir(path: string, callback: (error: HdfsError, files: any[]) => void): void {
public listStatus(path: string, callback: (error: HdfsError, files: FileStatus[]) => void): void {
this.checkArgDefined('path', path);
let endpoint = this.getOperationEndpoint('liststatus', path);
@@ -356,7 +356,21 @@ export class WebHDFS {
callback(error, undefined);
} else if (response.body.hasOwnProperty('FileStatuses')
&& response.body.FileStatuses.hasOwnProperty('FileStatus')) {
files = response.body.FileStatuses.FileStatus;
files = (<any[]>response.body.FileStatuses.FileStatus).map(fs => {
return new FileStatus(
fs.accessTime || '',
fs.blockSize || '',
fs.group || '',
fs.length || '',
fs.modificationTime || '',
fs.owner || '',
fs.pathSuffix || '',
fs.permission || '',
fs.replication || '',
fs.snapshotEnabled || '',
parseHdfsFileType(fs.type)
);
});
callback(undefined, files);
} else {
callback(new HdfsError(ErrorMessageInvalidDataStructure), undefined);
@@ -401,26 +415,6 @@ export class WebHDFS {
});
}
/**
* Get file status for given path
* @returns void
*/
public stat(path: string, callback: (error: HdfsError, fileStatus: any) => void): void {
this.checkArgDefined('path', path);
let endpoint = this.getOperationEndpoint('getfilestatus', path);
this.sendRequest('GET', endpoint, undefined, (error, response) => {
if (!callback) { return; }
if (error) {
callback(error, undefined);
} else if (response.body.hasOwnProperty('FileStatus')) {
callback(undefined, response.body.FileStatus);
} else {
callback(new HdfsError(ErrorMessageInvalidDataStructure), undefined);
}
});
}
public getFileStatus(path: string, callback: (error: HdfsError, fileStatus: FileStatus) => void): void {
this.checkArgDefined('path', path);
@@ -466,16 +460,45 @@ export class WebHDFS {
callback(error, undefined);
} else if (response.body.hasOwnProperty('AclStatus')) {
const permissions = parseAclPermissionFromOctal(response.body.AclStatus.permission);
const ownerEntry = new AclEntry(PermissionType.owner, '', `${response.body.AclStatus.owner || ''}${ownerPostfix}`);
ownerEntry.addPermission(AclEntryScope.access, permissions.owner);
const groupEntry = new AclEntry(PermissionType.group, '', `${response.body.AclStatus.group || ''}${owningGroupPostfix}`);
groupEntry.addPermission(AclEntryScope.access, permissions.group);
const otherEntry = new AclEntry(PermissionType.other, '', everyoneName);
otherEntry.addPermission(AclEntryScope.access, permissions.other);
const parsedEntries = parseAclList((<any[]>response.body.AclStatus.entries).join(','));
// First go through and apply any ACLs for the unnamed entries (which correspond to the permissions in
// the permission octal)
parsedEntries.filter(e => e.name === '').forEach(e => {
let targetEntry: AclEntry;
switch (e.type) {
case AclType.user:
targetEntry = ownerEntry;
break;
case AclType.group:
targetEntry = groupEntry;
break;
case AclType.other:
targetEntry = otherEntry;
break;
default:
// Unknown type - just ignore since we don't currently support the other types
return;
}
e.getAllPermissions().forEach( sp => {
targetEntry.addPermission(sp.scope, sp.permission);
});
});
const permissionStatus = new PermissionStatus(
new AclEntry(AclEntryScope.access, PermissionType.owner, '', response.body.AclStatus.owner || '', permissions.owner),
new AclEntry(AclEntryScope.access, PermissionType.group, '', response.body.AclStatus.group || '', permissions.group),
new AclEntry(AclEntryScope.access, PermissionType.other, '', everyoneName, permissions.other),
ownerEntry,
groupEntry,
otherEntry,
!!response.body.AclStatus.stickyBit,
// We filter out empty names here since those are already added by the permission bits - WebHDFS creates an extra ACL
// entry for the owning group whenever another ACL is added.
(<any[]>response.body.AclStatus.entries).map(entry => parseAcl(entry))
.reduce((acc, parsedEntries) => acc.concat(parsedEntries), [])
.filter(e => e.name !== ''));
// We filter out empty names here since those have already been merged into the
// owner/owning group/other entries
parsedEntries.filter(e => e.name !== ''));
callback(undefined, permissionStatus);
} else {
callback(new HdfsError(ErrorMessageInvalidDataStructure), undefined);
@@ -491,7 +514,6 @@ export class WebHDFS {
* @param otherEntry The entry corresponding to default permissions for all other users
* @param aclEntries The optional additional ACL entries to set
* @param callback Callback to handle the response
* @returns void
*/
public setAcl(path: string, ownerEntry: AclEntry, groupEntry: AclEntry, otherEntry: AclEntry, aclEntries: AclEntry[], callback: (error: HdfsError) => void): void {
this.checkArgDefined('path', path);
@@ -499,7 +521,8 @@ export class WebHDFS {
this.checkArgDefined('groupEntry', groupEntry);
this.checkArgDefined('otherEntry', otherEntry);
this.checkArgDefined('aclEntries', aclEntries);
const aclSpec = [ownerEntry, groupEntry, otherEntry].concat(aclEntries).map(entry => entry.toAclString()).join(',');
const concatEntries = [ownerEntry, groupEntry, otherEntry].concat(aclEntries);
const aclSpec = concatEntries.reduce((acc, entry) => acc.concat(entry.toAclStrings()), []).join(',');
let endpoint = this.getOperationEndpoint('setacl', path, { aclspec: aclSpec });
this.sendRequest('PUT', endpoint, undefined, (error) => {
return callback && callback(error);
@@ -510,6 +533,7 @@ export class WebHDFS {
* Sets the permission octal (sticky, owner, group & other) for a file/folder
* @param path The path to the file/folder to set the permission of
* @param permissionStatus The status containing the permission to set
* @param callback Callback to handle the response
*/
public setPermission(path: string, permissionStatus: PermissionStatus, callback: (error: HdfsError) => void): void {
this.checkArgDefined('path', path);
@@ -520,6 +544,19 @@ export class WebHDFS {
});
}
/**
* Removes the default ACLs for the specified path
* @param path The path to remove the default ACLs for
* @param callback Callback to handle the response
*/
public removeDefaultAcl(path: string, callback: (error: HdfsError) => void): void {
this.checkArgDefined('path', path);
let endpoint = this.getOperationEndpoint('removedefaultacl', path);
this.sendRequest('PUT', endpoint, undefined, (error) => {
return callback && callback(error);
});
}
/**
* Get all mounts for a HDFS connection
* @param callback Callback to handle the response
@@ -550,7 +587,7 @@ export class WebHDFS {
public exists(path: string, callback: (error: HdfsError, exists: boolean) => void): void {
this.checkArgDefined('path', path);
this.stat(path, (error, fileStatus) => {
this.listStatus(path, (error, fileStatus) => {
let exists = !fileStatus ? false : true;
callback(error, exists);
});