Skip to content

Commit

Permalink
added better validation of configuration settings
Browse files Browse the repository at this point in the history
use of defaults if no values were provided
  • Loading branch information
gbrueckl committed May 5, 2020
1 parent f82c147 commit c23eba2
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 44 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "databricks-vscode",
"displayName": "Databricks VSCode",
"description": "Databricks Extension for VSCode",
"version": "0.4.0",
"version": "0.4.1",
"publisher": "paiqo",
"icon": "resources/databricks_extension.png",
"author": {
Expand Down
24 changes: 8 additions & 16 deletions src/ThisExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { WorkspaceItemLanguage } from './databricksApi/workspaces/_types';
import { DatabricksConnectionManager } from './connections/DatabricksConnectionManager';
import { Helper } from './helpers/Helper';
import { DatabricksConnection } from './connections/DatabricksConnection';
import { iDatabricksConnection } from './connections/iDatabricksConnection';
import { DatabricksApiService } from './databricksApi/databricksApiService';

// https://vshaxe.github.io/vscode-extern/vscode/TreeDataProvider.html
export abstract class ThisExtension {
Expand Down Expand Up @@ -50,9 +52,11 @@ export abstract class ThisExtension {
this._context = context;
this._extension = vscode.extensions.getExtension(this.extension_id);

this.log("Initializing ConnectionManager ...");
this._connectionManager = new DatabricksConnectionManager();

this.validateSettings();
this.log("Initializing Databricks API Service ...");
DatabricksApiService.initialize();

this._keytar = require('keytar');
}
Expand Down Expand Up @@ -113,18 +117,6 @@ export abstract class ThisExtension {
}
}

static validateSettings(): void {
this.log("Validating settings ...");

if (this.ConnectionManager.Connections.length == 0) {
//vscode.window.showErrorMessage("No Connections have been configured! Please add new Connections using the VSCode Settings dialog!");
}

this._isValidated = true;

this.log("Settings validated!");
}

static get configuration(): vscode.Extension<any> {
return this._extension;
}
Expand All @@ -147,15 +139,15 @@ export type ExportFormatsConfiguration = {
SQL: string;
};

//
// represents the structure how the reference to the VSCode User settings are stored in the VSCode workspace settings
export interface iWorkspaceConfiguration {
workspaceGuid: string;
lastActiveConnection: string;
}

// represents the structure how the ExportFormats and FileExtensions for the different language are defined in the VS Code settings
// represents the structure how workspace configurations are stored in VSCode User Settings
export interface iUserWorkspaceConfiguration {
workspaceConfig: iWorkspaceConfiguration;
connections: DatabricksConnection[];
connections: iDatabricksConnection[];
}

83 changes: 79 additions & 4 deletions src/connections/DatabricksConnection.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as vscode from 'vscode';
import { CloudProvider } from './_types';
import { iDatabricksConnection } from './iDatabricksConnection';
import { ExportFormatsConfiguration } from '../ThisExtension';
import * as fspath from 'path';
import { ExportFormatsConfiguration, ThisExtension } from '../ThisExtension';

export class DatabricksConnection implements iDatabricksConnection {

Expand All @@ -17,13 +16,89 @@ export class DatabricksConnection implements iDatabricksConnection {
organizationId: string;
exportFormats: ExportFormatsConfiguration;

get isValid(): boolean {
if (this.displayName != undefined && this.displayName != "") {
constructor(
config: iDatabricksConnection
) {

this.displayName = config.displayName;
this.apiRootUrl = config.apiRootUrl;
this.cloudProvider = config.cloudProvider;
this.personalAccessToken = config.personalAccessToken;
this.localSyncFolder = config.localSyncFolder;
this.databricksConnectJars = config.databricksConnectJars;
this.pythonInterpreter = config.pythonInterpreter;
this.port = config.port;
this.organizationId = config.organizationId;
this.exportFormats = config.exportFormats;
}

private propertyIsValid(value): boolean {
if (value != undefined && value != null && value != "") {
return true;
}
return false;
}

validate(): boolean {
let msg: string = null;

// check mandatory properties and raise an error if necessary
if (!this.propertyIsValid(this.displayName)) {
msg = 'Configuration property "displayName" is not valid! Please check your user and/or workspace settings!';
ThisExtension.log(msg);
vscode.window.showErrorMessage(msg);
return false;
}
if (!this.propertyIsValid(this.apiRootUrl)) {
msg = 'Configuration ' + this.displayName + ': Property "apiRootUrl" is not valid! Please check your user and/or workspace settings!';
ThisExtension.log(msg);
vscode.window.showErrorMessage(msg);
return false;
}
if (!this.propertyIsValid(this.personalAccessToken)) {
msg = 'Configuration ' + this.displayName + ': Property "personalAccessToken" is not valid! Please check your user and/or workspace settings!';
ThisExtension.log(msg);
vscode.window.showErrorMessage(msg);
return false;
}
if (!this.propertyIsValid(this.localSyncFolder)) {
msg = 'Configuration ' + this.displayName + ': Property "localSyncFolder" is not valid! Please check your user and/or workspace settings!';
ThisExtension.log(msg);
vscode.window.showErrorMessage(msg);
return false;
}

// check defaultvalues, etc.
if (!this.propertyIsValid(this.exportFormats)) {
// get the default from the config of this extension
let defaultFromConfig = ThisExtension.configuration.packageJSON.contributes.configuration[0].properties["databricks.userWorkspaceConfigurations"].items.properties.connections.items.properties.exportFormats.default;
this.exportFormats = defaultFromConfig;
msg = 'Configuration ' + this.displayName + ': Property "exportFormats" was not provided - using the default value!';
ThisExtension.log(msg);
vscode.window.showWarningMessage(msg);
}
if (!this.propertyIsValid(this.cloudProvider)) {
if (this.apiRootUrl.includes('azuredatabricks')) {
this.cloudProvider = "Azure";
}
else {
this.cloudProvider = "AWS";
}
msg = 'Configuration ' + this.displayName + ': Setting Configuration property "cloudProvider" to "' + this.cloudProvider + '" based on the property "apiRootUrl"';
ThisExtension.log(msg);
}
if (!this.propertyIsValid(this.port) || this.port == 0) {
// get the default from the config of this extension
let defaultFromConfig = ThisExtension.configuration.packageJSON.contributes.configuration[0].properties["databricks.userWorkspaceConfigurations"].items.properties.connections.items.properties.port.default;
this.port = defaultFromConfig;
msg = 'Configuration ' + this.displayName + ': Property "port" was not provided - using the default value!';
ThisExtension.log(msg);
vscode.window.showWarningMessage(msg);
}

return true;
}

get allowAllSupportedFileExtensions(): boolean {
return true;
}
Expand Down
72 changes: 53 additions & 19 deletions src/connections/DatabricksConnectionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Helper } from '../helpers/Helper';
import { ExportFormatsConfiguration, iWorkspaceConfiguration, iUserWorkspaceConfiguration, ThisExtension } from '../ThisExtension';
import { DatabricksConnection } from './DatabricksConnection';
import { DatabricksApiService } from '../databricksApi/databricksApiService';
import { iDatabricksConnection } from './iDatabricksConnection';

export class DatabricksConnectionManager {

Expand All @@ -22,10 +23,17 @@ export class DatabricksConnectionManager {

this.loadConnections();

if (this._workspaceConfig.lastActiveConnection == undefined) {
this._workspaceConfig.lastActiveConnection = this._connections[0].displayName;
if (this.Connections.length == 0) {
let msg: string = "No connections have been configured yet! Please add a connection via the VSCode Settings -> Databricks before proceeding!";
ThisExtension.log(msg);
vscode.window.showErrorMessage(msg);
}
else {
if (this._workspaceConfig.lastActiveConnection == undefined) {
this._workspaceConfig.lastActiveConnection = this._connections[0].displayName;
}
this.activateConnection(this._workspaceConfig.lastActiveConnection);
}
this.activateConnection(this._workspaceConfig.lastActiveConnection);
}

loadConnections(): void {
Expand All @@ -43,7 +51,7 @@ export class DatabricksConnectionManager {
let defaultConnectionFromWorkspace = this.getDefaultConnectionFromWorkspace();
let connectionsFromUserConfig = this.getConnectionsFromUserConfig();

if (!this._connections.map((x) => x.displayName).includes(defaultConnectionFromWorkspace.displayName) && defaultConnectionFromWorkspace.isValid) {
if (defaultConnectionFromWorkspace != null && !this._connections.map((x) => x.displayName).includes(defaultConnectionFromWorkspace.displayName)) {
this._connections.push(defaultConnectionFromWorkspace);
}

Expand Down Expand Up @@ -78,33 +86,59 @@ export class DatabricksConnectionManager {
private getConnectionsFromUserConfig(): DatabricksConnection[] {
let currentUserWorkspaceConfig: iUserWorkspaceConfiguration = this.CurrentUserWorkspaceConfiguration;

let ret: DatabricksConnection[] = [];

if (currentUserWorkspaceConfig != undefined) {
return currentUserWorkspaceConfig.connections as DatabricksConnection[];
for (let con of currentUserWorkspaceConfig.connections) {
let dbCon = new DatabricksConnection(con);
if (dbCon.validate()) {
ret.push(dbCon);
}
}

return ret;
}
else {
return [];
}
}

private getConnectionsFromWorkspace(): DatabricksConnection[] {
let envs: DatabricksConnection[] = vscode.workspace.getConfiguration().get('databricks.connections');
let cons: iDatabricksConnection[] = vscode.workspace.getConfiguration().get('databricks.connections');

let ret: DatabricksConnection[] = [];

for (let con of cons) {
let dbCon = new DatabricksConnection(con);
if (dbCon.validate()) {
ret.push(dbCon);
}
}

return envs;
return ret;
}

private getDefaultConnectionFromWorkspace(): DatabricksConnection {
let defaultCon: DatabricksConnection = new DatabricksConnection();
defaultCon.displayName = vscode.workspace.getConfiguration().get('databricks.connection.default.displayName');
defaultCon.cloudProvider = vscode.workspace.getConfiguration().get('databricks.connection.default.cloudProvider');
defaultCon.apiRootUrl = vscode.workspace.getConfiguration().get('databricks.connection.default.apiRootUrl');
defaultCon.personalAccessToken = vscode.workspace.getConfiguration().get('databricks.connection.default.personalAccessToken');
defaultCon.localSyncFolder = vscode.workspace.getConfiguration().get('databricks.connection.default.localSyncFolder');

defaultCon.databricksConnectJars = vscode.workspace.getConfiguration().get('databricks.connection.default.databricksConnectJars');
defaultCon.pythonInterpreter = vscode.workspace.getConfiguration().get('databricks.connection.default.pythonInterpreter');
defaultCon.port = vscode.workspace.getConfiguration().get<number>('databricks.connection.default.port');
defaultCon.organizationId = vscode.workspace.getConfiguration().get('databricks.connection.default.organizationId');
defaultCon.exportFormats = vscode.workspace.getConfiguration().get<ExportFormatsConfiguration>('databricks.connection.default.exportFormats');

let con: iDatabricksConnection = {
displayName: vscode.workspace.getConfiguration().get('databricks.connection.default.displayName'),
cloudProvider: vscode.workspace.getConfiguration().get('databricks.connection.default.cloudProvider'),
apiRootUrl: vscode.workspace.getConfiguration().get('databricks.connection.default.apiRootUrl'),
personalAccessToken: vscode.workspace.getConfiguration().get('databricks.connection.default.personalAccessToken'),
localSyncFolder: vscode.workspace.getConfiguration().get('databricks.connection.default.localSyncFolder'),

databricksConnectJars: vscode.workspace.getConfiguration().get('databricks.connection.default.databricksConnectJars'),
pythonInterpreter: vscode.workspace.getConfiguration().get('databricks.connection.default.pythonInterpreter'),
port: vscode.workspace.getConfiguration().get<number>('databricks.connection.default.port'),
organizationId: vscode.workspace.getConfiguration().get('databricks.connection.default.organizationId'),
exportFormats: vscode.workspace.getConfiguration().get<ExportFormatsConfiguration>('databricks.connection.default.exportFormats')
};

let defaultCon: DatabricksConnection = new DatabricksConnection(con);

if (defaultCon.displayName == "" || !defaultCon.validate()) {
return null;
}

return defaultCon;
}
Expand Down
6 changes: 2 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import * as vscode from 'vscode';
import { ThisExtension } from './ThisExtension';
import { Helper } from './helpers/Helper';

import { DatabricksApiService } from './databricksApi/databricksApiService';
import { DatabricksConnectionTreeProvider } from './DatabricksConnectionTreeProvider';
import { DatabricksConnectionTreeItem } from './connections/DatabricksConnectionTreeItem';
import { DatabricksWorkspaceTreeProvider } from './DatabricksWorkspaceTreeProvider';
Expand All @@ -27,13 +25,13 @@ export function activate(context: vscode.ExtensionContext) {
vscode.window.showErrorMessage("Please update Databricks settings and restart VSCode!");
}

/*
ThisExtension.setSecureSetting("myTest", "Pass@word123").then(
(x) => ThisExtension.getSecureSetting("myTest").then(
(y) => ThisExtension.log(y)
)
);

DatabricksApiService.initialize();
*/

// register DatabricksConnectionTreeProvider
let databricksConnectionTreeProvider = new DatabricksConnectionTreeProvider();
Expand Down

0 comments on commit c23eba2

Please sign in to comment.