Allow 'ApplicationName' to be specified for MSSQL connections (#22890)

This commit is contained in:
Cheena Malhotra
2023-05-01 10:55:05 -07:00
committed by GitHub
parent f4952c76b8
commit ea6bb41f45
12 changed files with 81 additions and 39 deletions

View File

@@ -143,6 +143,20 @@
"isRequired": true, "isRequired": true,
"isArray": false "isArray": false
}, },
{
"specialValueType": null,
"isIdentity": false,
"name": "applicationName",
"displayName": "%cms.connectionOptions.applicationName.displayName%",
"description": "%cms.connectionOptions.applicationName.description%",
"groupName": "%cms.connectionOptions.groupName.initialization%",
"valueType": "string",
"defaultValue": null,
"objectType": null,
"categoryValues": null,
"isRequired": false,
"isArray": false
},
{ {
"specialValueType": null, "specialValueType": null,
"isIdentity": false, "isIdentity": false,
@@ -466,20 +480,6 @@
"isRequired": false, "isRequired": false,
"isArray": false "isArray": false
}, },
{
"specialValueType": "appName",
"isIdentity": false,
"name": "applicationName",
"displayName": "%cms.connectionOptions.applicationName.displayName%",
"description": "%cms.connectionOptions.applicationName.description%",
"groupName": "%cms.connectionOptions.groupName.context%",
"valueType": "string",
"defaultValue": null,
"objectType": null,
"categoryValues": null,
"isRequired": false,
"isArray": false
},
{ {
"specialValueType": null, "specialValueType": null,
"isIdentity": false, "isIdentity": false,

View File

@@ -1,6 +1,6 @@
{ {
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
"version": "4.7.0.22", "version": "4.7.0.23",
"downloadFileNames": { "downloadFileNames": {
"Windows_86": "win-x86-net7.0.zip", "Windows_86": "win-x86-net7.0.zip",
"Windows_64": "win-x64-net7.0.zip", "Windows_64": "win-x64-net7.0.zip",
@@ -10,7 +10,10 @@
"Linux": "rhel-x64-net7.0.tar.gz" "Linux": "rhel-x64-net7.0.tar.gz"
}, },
"installDirectory": "./sqltoolsservice/{#platform#}/{#version#}", "installDirectory": "./sqltoolsservice/{#platform#}/{#version#}",
"executableFiles": ["MicrosoftSqlToolsServiceLayer.exe", "MicrosoftSqlToolsServiceLayer"], "executableFiles": [
"MicrosoftSqlToolsServiceLayer.exe",
"MicrosoftSqlToolsServiceLayer"
],
"retry": { "retry": {
"retries": 15, "retries": 15,
"factor": 2, "factor": 2,

View File

@@ -900,6 +900,20 @@
"isRequired": true, "isRequired": true,
"isArray": false "isArray": false
}, },
{
"specialValueType": null,
"isIdentity": false,
"name": "applicationName",
"displayName": "%mssql.connectionOptions.applicationName.displayName%",
"description": "%mssql.connectionOptions.applicationName.description%",
"groupName": "%mssql.connectionOptions.groupName.initialization%",
"valueType": "string",
"defaultValue": null,
"objectType": null,
"categoryValues": null,
"isRequired": false,
"isArray": false
},
{ {
"specialValueType": null, "specialValueType": null,
"isIdentity": false, "isIdentity": false,
@@ -1236,20 +1250,6 @@
"isRequired": false, "isRequired": false,
"isArray": false "isArray": false
}, },
{
"specialValueType": "appName",
"isIdentity": false,
"name": "applicationName",
"displayName": "%mssql.connectionOptions.applicationName.displayName%",
"description": "%mssql.connectionOptions.applicationName.description%",
"groupName": "%mssql.connectionOptions.groupName.context%",
"valueType": "string",
"defaultValue": null,
"objectType": null,
"categoryValues": null,
"isRequired": false,
"isArray": false
},
{ {
"specialValueType": null, "specialValueType": null,
"isIdentity": false, "isIdentity": false,

View File

@@ -184,7 +184,7 @@ function getSqlDbConnectionProfile(
savePassword: false, savePassword: false,
saveProfile: false, saveProfile: false,
options: { options: {
conectionName: '', connectionName: '',
server: serverName, server: serverName,
database: databaseName, database: databaseName,
authenticationType: azdata.connection.AuthenticationType.SqlLogin, authenticationType: azdata.connection.AuthenticationType.SqlLogin,
@@ -197,7 +197,7 @@ function getSqlDbConnectionProfile(
trustServerCertificate: false, trustServerCertificate: false,
connectRetryCount: '1', connectRetryCount: '1',
connectRetryInterval: '10', connectRetryInterval: '10',
applicationName: 'azdata', applicationName: 'azdata-sqlMigration',
azureTenantId: tenantId, azureTenantId: tenantId,
originalDatabase: databaseName, originalDatabase: databaseName,
databaseDisplayName: databaseName, databaseDisplayName: databaseName,
@@ -228,7 +228,7 @@ export function getTargetConnectionProfile(
providerName: 'MSSQL', providerName: 'MSSQL',
saveProfile: false, saveProfile: false,
options: { options: {
conectionName: connectId, connectionName: connectId,
server: serverName, server: serverName,
authenticationType: azdata.connection.AuthenticationType.SqlLogin, authenticationType: azdata.connection.AuthenticationType.SqlLogin,
user: userName, user: userName,
@@ -239,9 +239,9 @@ export function getTargetConnectionProfile(
trustServerCertificate: trustServerCert, trustServerCertificate: trustServerCert,
connectRetryCount: '1', connectRetryCount: '1',
connectRetryInterval: '10', connectRetryInterval: '10',
applicationName: 'azdata', applicationName: 'azdata-sqlMigration',
}, },
}; }
} }
export async function getSourceConnectionString(): Promise<string> { export async function getSourceConnectionString(): Promise<string> {

View File

@@ -13,6 +13,7 @@ import { isString } from 'vs/base/common/types';
import { deepClone } from 'vs/base/common/objects'; import { deepClone } from 'vs/base/common/objects';
import * as Constants from 'sql/platform/connection/common/constants'; import * as Constants from 'sql/platform/connection/common/constants';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { adjustForMssqlAppName } from 'sql/platform/connection/common/utils';
export interface IconPath { export interface IconPath {
light: URI; light: URI;
@@ -65,10 +66,17 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
let capabilities = this.capabilitiesService.getCapabilities(this.providerName); let capabilities = this.capabilitiesService.getCapabilities(this.providerName);
if (capabilities && capabilities.connection && capabilities.connection.connectionOptions) { if (capabilities && capabilities.connection && capabilities.connection.connectionOptions) {
const options = capabilities.connection.connectionOptions; const options = capabilities.connection.connectionOptions;
// MSSQL Provider doesn't treat appName as special type anymore.
let appNameOption = options.find(option => option.specialValueType === interfaces.ConnectionOptionSpecialType.appName); let appNameOption = options.find(option => option.specialValueType === interfaces.ConnectionOptionSpecialType.appName);
if (appNameOption) { if (appNameOption) {
let appNameKey = appNameOption.name; let appNameKey = appNameOption.name;
this.options[appNameKey] = Constants.applicationName; this.options[appNameKey] = Constants.applicationName;
} else if (this.providerName === Constants.mssqlProviderName || this.providerName === Constants.mssqlCmsProviderName) {
// Update AppName here for MSSQL and MSSQL-CMS provider to be able to match connection URI with STS.
appNameOption = options.find(option => option.name === Constants.mssqlApplicationNameOption);
if (appNameOption) {
this.options[Constants.mssqlApplicationNameOption] = adjustForMssqlAppName(model.options[Constants.mssqlApplicationNameOption]);
}
} }
// Set values for advanced options received in model. // Set values for advanced options received in model.
Object.keys(model.options).forEach(a => { Object.keys(model.options).forEach(a => {

View File

@@ -11,12 +11,14 @@ export const outputChannelName = 'MSSQL';
export const capabilitiesOptions = 'OPTIONS_METADATA'; export const capabilitiesOptions = 'OPTIONS_METADATA';
export const mssqlProviderName = 'MSSQL'; export const mssqlProviderName = 'MSSQL';
export const mssqlCmsProviderName = 'MSSQL-CMS';
export const mysqlProviderName = 'MYSQL'; export const mysqlProviderName = 'MYSQL';
export const pgsqlProviderName = 'PGSQL'; export const pgsqlProviderName = 'PGSQL';
export const anyProviderName = '*'; export const anyProviderName = '*';
export const connectionProviderContextKey = 'connectionProvider'; export const connectionProviderContextKey = 'connectionProvider';
export const applicationName = 'azdata'; export const applicationName = 'azdata';
export const mssqlApplicationNameOption = 'applicationName';
export const defaultEngine = 'defaultEngine'; export const defaultEngine = 'defaultEngine';

View File

@@ -7,6 +7,7 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
import * as sqlExtHostTypes from 'sql/workbench/api/common/sqlExtHostTypes'; import * as sqlExtHostTypes from 'sql/workbench/api/common/sqlExtHostTypes';
import { applicationName } from 'sql/platform/connection/common/constants';
// CONSTANTS ////////////////////////////////////////////////////////////////////////////////////// // CONSTANTS //////////////////////////////////////////////////////////////////////////////////////
const msInH = 3.6e6; const msInH = 3.6e6;
@@ -170,3 +171,11 @@ export function convertToRpcConnectionProfile(profile: IConnectionProfile | unde
return connection; return connection;
} }
export function adjustForMssqlAppName(currentAppName: string, suffix?: string): string {
let appName = suffix ? applicationName + '-' + suffix : applicationName;
let finalSuffix = '-' + appName;
return (currentAppName && currentAppName !== appName && !currentAppName.endsWith(finalSuffix))
? currentAppName + finalSuffix
: currentAppName ?? appName;
}

View File

@@ -41,6 +41,7 @@ export interface SqlArgs {
aad?: boolean; // deprecated - used by SSMS - authenticationType should be used instead aad?: boolean; // deprecated - used by SSMS - authenticationType should be used instead
integrated?: boolean; // deprecated - used by SSMS - authenticationType should be used instead. integrated?: boolean; // deprecated - used by SSMS - authenticationType should be used instead.
showDashboard?: boolean; showDashboard?: boolean;
applicationName?: string;
} }
//#region decorators //#region decorators
@@ -307,7 +308,10 @@ export class CommandLineWorkbenchContribution implements IWorkbenchContribution,
Constants.AuthenticationType.Integrated; Constants.AuthenticationType.Integrated;
profile.connectionName = ''; profile.connectionName = '';
profile.setOptionValue('applicationName', Constants.applicationName); const applicationName = args.applicationName
? args.applicationName + '-' + Constants.applicationName
: Constants.applicationName;
profile.setOptionValue('applicationName', applicationName);
profile.setOptionValue('databaseDisplayName', profile.databaseName); profile.setOptionValue('databaseDisplayName', profile.databaseName);
profile.setOptionValue('groupId', profile.groupId); profile.setOptionValue('groupId', profile.groupId);
return this._connectionManagementService ? this.tryMatchSavedProfile(profile) : profile; return this._connectionManagementService ? this.tryMatchSavedProfile(profile) : profile;

View File

@@ -95,6 +95,7 @@ class TestParsedArgs implements NativeParsedArgs, SqlArgs {
wait?: boolean; wait?: boolean;
waitMarkerFilePath?: string; waitMarkerFilePath?: string;
authenticationType?: string; authenticationType?: string;
applicationName?: string;
} }
suite('commandLineService tests', () => { suite('commandLineService tests', () => {
@@ -196,12 +197,14 @@ suite('commandLineService tests', () => {
args.database = 'mydatabase'; args.database = 'mydatabase';
args.user = 'myuser'; args.user = 'myuser';
args.authenticationType = Constants.AuthenticationType.SqlLogin; args.authenticationType = Constants.AuthenticationType.SqlLogin;
args.applicationName = 'myapplication';
connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never()); connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never());
connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce()); connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce());
connectionManagementService.setup(c => c.getConnectionGroups(TypeMoq.It.isAny())).returns(() => []); connectionManagementService.setup(c => c.getConnectionGroups(TypeMoq.It.isAny())).returns(() => []);
let originalProfile: IConnectionProfile = undefined; let originalProfile: IConnectionProfile = undefined;
connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.is<ConnectionProfile>(p => p.serverName === 'myserver' && p.authenticationType === Constants.AuthenticationType.SqlLogin), 'connection', true)) connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.is<ConnectionProfile>(
p => p.serverName === 'myserver' && p.authenticationType === Constants.AuthenticationType.SqlLogin && p.options['applicationName'] === 'myapplication-azdata'), 'connection', true))
.returns((conn) => { .returns((conn) => {
originalProfile = conn; originalProfile = conn;
return Promise.resolve('unused'); return Promise.resolve('unused');
@@ -212,6 +215,7 @@ suite('commandLineService tests', () => {
const logService = new NullLogService(); const logService = new NullLogService();
let contribution = getCommandLineContribution(connectionManagementService.object, configurationService.object, capabilitiesService, undefined, undefined, logService); let contribution = getCommandLineContribution(connectionManagementService.object, configurationService.object, capabilitiesService, undefined, undefined, logService);
await contribution.processCommandLine(args); await contribution.processCommandLine(args);
assert.equal(originalProfile.options['applicationName'], 'myapplication-azdata', 'Application Name not received as expected.');
connectionManagementService.verifyAll(); connectionManagementService.verifyAll();
}); });

View File

@@ -160,10 +160,16 @@ export class ConnectionController implements IConnectionComponentController {
this._connectionWidget.updateServerGroup(this.getAllServerGroups(providers)); this._connectionWidget.updateServerGroup(this.getAllServerGroups(providers));
this._model = connectionInfo; this._model = connectionInfo;
this._model.providerName = this._providerName; this._model.providerName = this._providerName;
// MSSQL and MSSQL-CMS Provider don't treat appName as special type anymore.
let appNameOption = this._providerOptions.find(option => option.specialValueType === ConnectionOptionSpecialType.appName); let appNameOption = this._providerOptions.find(option => option.specialValueType === ConnectionOptionSpecialType.appName);
if (appNameOption) { if (appNameOption) {
let appNameKey = appNameOption.name; let appNameKey = appNameOption.name;
this._model.options[appNameKey] = Constants.applicationName; this._model.options[appNameKey] = Constants.applicationName;
} else {
appNameOption = this._providerOptions.find(option => option.name === Constants.mssqlApplicationNameOption);
if (appNameOption && (this._model.providerName === Constants.mssqlProviderName || this._model.providerName === Constants.mssqlCmsProviderName)) {
this._model.options[Constants.mssqlApplicationNameOption] = Utils.adjustForMssqlAppName(this._model.options[Constants.mssqlApplicationNameOption]);
}
} }
this._connectionWidget.initDialog(this._model); this._connectionWidget.initDialog(this._model);
} }

View File

@@ -38,10 +38,11 @@ import { ConnectionStringOptions } from 'sql/platform/capabilities/common/capabi
import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { filterAccounts } from 'sql/workbench/services/accountManagement/browser/accountDialog'; import { filterAccounts } from 'sql/workbench/services/accountManagement/browser/accountDialog';
import { AuthenticationType, Actions } from 'sql/platform/connection/common/constants'; import { AuthenticationType, Actions, mssqlApplicationNameOption, applicationName, mssqlProviderName, mssqlCmsProviderName } from 'sql/platform/connection/common/constants';
import { AdsWidget } from 'sql/base/browser/ui/adsWidget'; import { AdsWidget } from 'sql/base/browser/ui/adsWidget';
import { createCSSRule } from 'vs/base/browser/dom'; import { createCSSRule } from 'vs/base/browser/dom';
import { AuthLibrary, getAuthLibrary } from 'sql/workbench/services/accountManagement/utils'; import { AuthLibrary, getAuthLibrary } from 'sql/workbench/services/accountManagement/utils';
import { adjustForMssqlAppName } from 'sql/platform/connection/common/utils';
const ConnectionStringText = localize('connectionWidget.connectionString', "Connection string"); const ConnectionStringText = localize('connectionWidget.connectionString', "Connection string");
@@ -1253,6 +1254,11 @@ export class ConnectionWidget extends lifecycle.Disposable {
}); });
} }
} }
// Fix Application Name for MSSQL/MSSQL-CMS Providers, to handle special case as we need to apply custom application name in ADS Core connection profile.
if ((model.providerName === mssqlProviderName || model.providerName === mssqlCmsProviderName)
&& model.options[mssqlApplicationNameOption] && !model.options[mssqlApplicationNameOption].endsWith(applicationName)) {
model.options[mssqlApplicationNameOption] = adjustForMssqlAppName(model.options[mssqlApplicationNameOption]);
}
model.connectionName = this.connectionName; model.connectionName = this.connectionName;
if (this._serverGroupSelectBox) { if (this._serverGroupSelectBox) {
if (this._serverGroupSelectBox.value === this.DefaultServerGroup.name) { if (this._serverGroupSelectBox.value === this.DefaultServerGroup.name) {