mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
New UI for deploying SQL project to a new Azure server (#18833)
This commit is contained in:
@@ -23,11 +23,13 @@ export class MockVscodeMssqlIExtension implements vscodeMssql.IExtension {
|
|||||||
dacFx: vscodeMssql.IDacFxService;
|
dacFx: vscodeMssql.IDacFxService;
|
||||||
schemaCompare: vscodeMssql.ISchemaCompareService;
|
schemaCompare: vscodeMssql.ISchemaCompareService;
|
||||||
azureAccountService: vscodeMssql.IAzureAccountService;
|
azureAccountService: vscodeMssql.IAzureAccountService;
|
||||||
|
azureResourceService: vscodeMssql.IAzureResourceService;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.dacFx = TypeMoq.Mock.ofType<vscodeMssql.IDacFxService>().object;
|
this.dacFx = TypeMoq.Mock.ofType<vscodeMssql.IDacFxService>().object;
|
||||||
this.schemaCompare = TypeMoq.Mock.ofType<vscodeMssql.ISchemaCompareService>().object;
|
this.schemaCompare = TypeMoq.Mock.ofType<vscodeMssql.ISchemaCompareService>().object;
|
||||||
this.azureAccountService = TypeMoq.Mock.ofType<vscodeMssql.IAzureAccountService>().object;
|
this.azureAccountService = TypeMoq.Mock.ofType<vscodeMssql.IAzureAccountService>().object;
|
||||||
|
this.azureResourceService = TypeMoq.Mock.ofType<vscodeMssql.IAzureResourceService>().object;
|
||||||
}
|
}
|
||||||
|
|
||||||
promptForFirewallRule(_: string, __: vscodeMssql.IConnectionInfo): Promise<boolean> {
|
promptForFirewallRule(_: string, __: vscodeMssql.IConnectionInfo): Promise<boolean> {
|
||||||
|
|||||||
@@ -464,7 +464,7 @@
|
|||||||
"vscode-languageclient": "^5.3.0-next.1",
|
"vscode-languageclient": "^5.3.0-next.1",
|
||||||
"vscode-nls": "^4.1.2",
|
"vscode-nls": "^4.1.2",
|
||||||
"which": "^2.0.2",
|
"which": "^2.0.2",
|
||||||
"xml-formatter": "^2.1.0",
|
"xml-formatter": "2.1.0",
|
||||||
"xmldom": "^0.6.0"
|
"xmldom": "^0.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -149,9 +149,16 @@ export const nameMustNotBeEmpty = localize('nameMustNotBeEmpty', "Name must not
|
|||||||
// Deploy
|
// Deploy
|
||||||
export const SqlServerName = 'SQL server';
|
export const SqlServerName = 'SQL server';
|
||||||
export const AzureSqlServerName = 'Azure SQL server';
|
export const AzureSqlServerName = 'Azure SQL server';
|
||||||
|
export const AzureSqlLogicalServerName = 'Azure SQL logical server';
|
||||||
export const selectPublishOption = localize('selectPublishOption', "Select where to publish the project to");
|
export const selectPublishOption = localize('selectPublishOption', "Select where to publish the project to");
|
||||||
export function publishToExistingServer(name: string) { return localize('publishToExistingServer', "Publish to an existing {0}", name); }
|
export function publishToExistingServer(name: string) { return localize('publishToExistingServer', "Publish to an existing {0}", name); }
|
||||||
export function publishToDockerContainer(name: string) { return localize('publishToDockerContainer', "Publish to new {0} local development container", name); }
|
export function publishToDockerContainer(name: string) { return localize('publishToDockerContainer', "Publish to new {0} local development container", name); }
|
||||||
|
export const publishToNewAzureServer = localize('publishToNewAzureServer', "Publish to new Azure SQL logical server");
|
||||||
|
export const azureServerName = localize('azureServerName', "Azure SQL server name");
|
||||||
|
export const azureSubscription = localize('azureSubscription', "Azure subscription");
|
||||||
|
export const resourceGroup = localize('resourceGroup', "Resource group");
|
||||||
|
export const azureLocation = localize('location', "Location");
|
||||||
|
export const azureAccounts = localize('azureAccounts', "Azure accounts");
|
||||||
export function enterPortNumber(name: string) { return localize('enterPortNumber', "Enter {0} port number or press enter to use the default value", name); }
|
export function enterPortNumber(name: string) { return localize('enterPortNumber', "Enter {0} port number or press enter to use the default value", name); }
|
||||||
export function serverPortNumber(name: string) { return localize('serverPortNumber', "{0} port number", name); }
|
export function serverPortNumber(name: string) { return localize('serverPortNumber', "{0} port number", name); }
|
||||||
export function serverPassword(name: string) { return localize('serverPassword', "{0} admin password", name); }
|
export function serverPassword(name: string) { return localize('serverPassword', "{0} admin password", name); }
|
||||||
@@ -160,6 +167,7 @@ export function baseDockerImage(name: string) { return localize('baseDockerImage
|
|||||||
export const publishTo = localize('publishTo', "Publish Target");
|
export const publishTo = localize('publishTo', "Publish Target");
|
||||||
export const enterConnectionStringEnvName = localize('enterConnectionStringEnvName', "Enter connection string environment variable name");
|
export const enterConnectionStringEnvName = localize('enterConnectionStringEnvName', "Enter connection string environment variable name");
|
||||||
export const enterConnectionStringTemplate = localize('enterConnectionStringTemplate', "Enter connection string template");
|
export const enterConnectionStringTemplate = localize('enterConnectionStringTemplate', "Enter connection string template");
|
||||||
|
export function enterUser(name: string) { return localize('enterUser', "Enter {0} admin user name", name); }
|
||||||
export function enterPassword(name: string) { return localize('enterPassword', "Enter {0} admin password", name); }
|
export function enterPassword(name: string) { return localize('enterPassword', "Enter {0} admin password", name); }
|
||||||
export function confirmPassword(name: string) { return localize('confirmPassword', "Confirm {0} admin password", name); }
|
export function confirmPassword(name: string) { return localize('confirmPassword', "Confirm {0} admin password", name); }
|
||||||
export function selectBaseImage(name: string) { return localize('selectBaseImage', "Select the base {0} docker image", name); }
|
export function selectBaseImage(name: string) { return localize('selectBaseImage', "Select the base {0} docker image", name); }
|
||||||
@@ -205,12 +213,16 @@ export const runningDockerMessage = localize('runningDockerMessage', "Running th
|
|||||||
export function dockerNotRunningError(error: string) { return localize('dockerNotRunningError', "Failed to verify docker. Please make sure docker is installed and running. Error: '{0}'", error || ''); }
|
export function dockerNotRunningError(error: string) { return localize('dockerNotRunningError', "Failed to verify docker. Please make sure docker is installed and running. Error: '{0}'", error || ''); }
|
||||||
export const dockerContainerNotRunningErrorMessage = localize('dockerContainerNotRunningErrorMessage', "Docker container is not running");
|
export const dockerContainerNotRunningErrorMessage = localize('dockerContainerNotRunningErrorMessage', "Docker container is not running");
|
||||||
export const dockerContainerFailedToRunErrorMessage = localize('dockerContainerFailedToRunErrorMessage', "Failed to run the docker container");
|
export const dockerContainerFailedToRunErrorMessage = localize('dockerContainerFailedToRunErrorMessage', "Failed to run the docker container");
|
||||||
export const connectingToSqlServerMessage = localize('connectingToSqlServerOnDockerMessage', "Connecting to SQL Server");
|
export const connectingToSqlServerMessage = localize('connectingToSqlServerMessage', "Connecting to SQL Server");
|
||||||
|
export const serverCreated = localize('serverCreated', "Server created");
|
||||||
export const deployProjectFailedMessage = localize('deployProjectFailedMessage', "Failed to open a connection to the deployed database'");
|
export const deployProjectFailedMessage = localize('deployProjectFailedMessage', "Failed to open a connection to the deployed database'");
|
||||||
export const containerAlreadyExistForProject = localize('containerAlreadyExistForProject', "Containers already exist for this project. Do you want to delete them before deploying a new one?");
|
export const containerAlreadyExistForProject = localize('containerAlreadyExistForProject', "Containers already exist for this project. Do you want to delete them before deploying a new one?");
|
||||||
export const checkoutOutputMessage = localize('checkoutOutputMessage', "Check output pane for more details");
|
export const checkoutOutputMessage = localize('checkoutOutputMessage', "Check output pane for more details");
|
||||||
|
export function creatingAzureSqlServer(name: string): string { return localize('creatingAzureSqlServer', "Creating Azure SQL Server '{0}' ...", name); }
|
||||||
|
export function azureSqlServerCreated(name: string): string { return localize('azureSqlServerCreated', "Azure SQL Server '{0}' created", name); }
|
||||||
export function taskFailedError(taskName: string, err: string): string { return localize('taskFailedError.error', "Failed to complete task '{0}'. Error: {1}", taskName, err); }
|
export function taskFailedError(taskName: string, err: string): string { return localize('taskFailedError.error', "Failed to complete task '{0}'. Error: {1}", taskName, err); }
|
||||||
export function publishToContainerFailed(errorMessage: string) { return localize('publishToContainerFailed', "Failed to publish to container. {0}", errorMessage); }
|
export function publishToContainerFailed(errorMessage: string) { return localize('publishToContainerFailed', "Failed to publish to container. {0}", errorMessage); }
|
||||||
|
export function publishToNewAzureServerFailed(errorMessage: string) { return localize('publishToNewAzureServerFailed', "Failed to publish to new Azure SQL server. {0}", errorMessage); }
|
||||||
export function deployAppSettingUpdateFailed(appSetting: string) { return localize('deployAppSettingUpdateFailed', "Failed to update app setting '{0}'", appSetting); }
|
export function deployAppSettingUpdateFailed(appSetting: string) { return localize('deployAppSettingUpdateFailed', "Failed to update app setting '{0}'", appSetting); }
|
||||||
export function deployAppSettingUpdating(appSetting: string) { return localize('deployAppSettingUpdating', "Updating app setting: '{0}'", appSetting); }
|
export function deployAppSettingUpdating(appSetting: string) { return localize('deployAppSettingUpdating', "Updating app setting: '{0}'", appSetting); }
|
||||||
export function connectionFailedError(error: string) { return localize('connectionFailedError', "Connection failed error: '{0}'", error); }
|
export function connectionFailedError(error: string) { return localize('connectionFailedError', "Connection failed error: '{0}'", error); }
|
||||||
@@ -220,7 +232,7 @@ export function retryWaitMessage(numberOfSeconds: number, name: string) { return
|
|||||||
export function retryRunMessage(attemptNumber: number, numberOfAttempts: number, name: string) { return localize('retryRunMessage', "Running operation '{2}' Attempt {0} of {1}", attemptNumber, numberOfAttempts, name); }
|
export function retryRunMessage(attemptNumber: number, numberOfAttempts: number, name: string) { return localize('retryRunMessage', "Running operation '{2}' Attempt {0} of {1}", attemptNumber, numberOfAttempts, name); }
|
||||||
export function retrySucceedMessage(name: string, result: string) { return localize('retrySucceedMessage', "Operation '{0}' completed successfully. Result: {1}", name, result); }
|
export function retrySucceedMessage(name: string, result: string) { return localize('retrySucceedMessage', "Operation '{0}' completed successfully. Result: {1}", name, result); }
|
||||||
export function retryFailedMessage(name: string, result: string, error: string) { return localize('retryFailedMessage', "Operation '{0}' failed. Re-trying... Current Result: {1}. Error: '{2}'", name, result, error); }
|
export function retryFailedMessage(name: string, result: string, error: string) { return localize('retryFailedMessage', "Operation '{0}' failed. Re-trying... Current Result: {1}. Error: '{2}'", name, result, error); }
|
||||||
export function retryMessage(name: string, error: string) { return localize('retryMessage', "Operation '{0}' failed. Re-trying... Error: '{1}'", name, error || ''); }
|
export function retryMessage(name: string, error: string) { return localize('retryMessage', "Operation '{0}' failed. Re-trying... Error: '{1}' ", name, error); }
|
||||||
|
|
||||||
// Add Database Reference dialog strings
|
// Add Database Reference dialog strings
|
||||||
|
|
||||||
@@ -492,6 +504,8 @@ export const integratedAuth = 'Integrated';
|
|||||||
export const azureMfaAuth = 'AzureMFA';
|
export const azureMfaAuth = 'AzureMFA';
|
||||||
export const sqlAuth = 'SqlAuth';
|
export const sqlAuth = 'SqlAuth';
|
||||||
|
|
||||||
|
export const azureAddAccount = localize('azureAddAccount', "Add an Account...");
|
||||||
|
|
||||||
// Tree item types
|
// Tree item types
|
||||||
export enum DatabaseProjectItemType {
|
export enum DatabaseProjectItemType {
|
||||||
project = 'databaseProject.itemType.project',
|
project = 'databaseProject.itemType.project',
|
||||||
@@ -560,4 +574,5 @@ export function getTargetPlatformFromVersion(version: string): string {
|
|||||||
export enum PublishTargetType {
|
export enum PublishTargetType {
|
||||||
existingServer = 'existingServer',
|
existingServer = 'existingServer',
|
||||||
docker = 'docker',
|
docker = 'docker',
|
||||||
|
newAzureServer = 'newAzureServer'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,5 +39,6 @@ export enum TelemetryActions {
|
|||||||
createProjectFromDatabase = 'createProjectFromDatabase',
|
createProjectFromDatabase = 'createProjectFromDatabase',
|
||||||
updateProjectFromDatabase = 'updateProjectFromDatabase',
|
updateProjectFromDatabase = 'updateProjectFromDatabase',
|
||||||
publishToContainer = 'publishToContainer',
|
publishToContainer = 'publishToContainer',
|
||||||
|
publishToNewAzureServer = 'publishToNewAzureServer',
|
||||||
generateProjectFromOpenApiSpec = 'generateProjectFromOpenApiSpec'
|
generateProjectFromOpenApiSpec = 'generateProjectFromOpenApiSpec'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -307,6 +307,18 @@ export async function getVscodeMssqlApi(): Promise<vscodeMssql.IExtension> {
|
|||||||
return ext.activate();
|
return ext.activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AzureResourceServiceFactory = () => Promise<vscodeMssql.IAzureResourceService>;
|
||||||
|
export async function defaultAzureResourceServiceFactory(): Promise<vscodeMssql.IAzureResourceService> {
|
||||||
|
const vscodeMssqlApi = await getVscodeMssqlApi();
|
||||||
|
return vscodeMssqlApi.azureResourceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AzureAccountServiceFactory = () => Promise<vscodeMssql.IAzureAccountService>;
|
||||||
|
export async function defaultAzureAccountServiceFactory(): Promise<vscodeMssql.IAzureAccountService> {
|
||||||
|
const vscodeMssqlApi = await getVscodeMssqlApi();
|
||||||
|
return vscodeMssqlApi.azureAccountService;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the default deployment options from DacFx, filtered to appropriate options for the given project.
|
* Returns the default deployment options from DacFx, filtered to appropriate options for the given project.
|
||||||
*/
|
*/
|
||||||
@@ -441,7 +453,7 @@ export async function retry<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
outputChannel.appendLine(constants.retryMessage(name, err));
|
outputChannel.appendLine(constants.retryMessage(name, getErrorMessage(err)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,16 +38,17 @@ import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/t
|
|||||||
import { IconPathHelper } from '../common/iconHelper';
|
import { IconPathHelper } from '../common/iconHelper';
|
||||||
import { DashboardData, PublishData, Status } from '../models/dashboardData/dashboardData';
|
import { DashboardData, PublishData, Status } from '../models/dashboardData/dashboardData';
|
||||||
import { getPublishDatabaseSettings, launchPublishTargetOption } from '../dialogs/publishDatabaseQuickpick';
|
import { getPublishDatabaseSettings, launchPublishTargetOption } from '../dialogs/publishDatabaseQuickpick';
|
||||||
import { launchPublishToDockerContainerQuickpick } from '../dialogs/deployDatabaseQuickpick';
|
import { launchCreateAzureServerQuickPick, launchPublishToDockerContainerQuickpick } from '../dialogs/deployDatabaseQuickpick';
|
||||||
import { DeployService } from '../models/deploy/deployService';
|
import { DeployService } from '../models/deploy/deployService';
|
||||||
import { GenerateProjectFromOpenApiSpecOptions, SqlTargetPlatform } from 'sqldbproj';
|
import { GenerateProjectFromOpenApiSpecOptions, SqlTargetPlatform } from 'sqldbproj';
|
||||||
import { AutorestHelper } from '../tools/autorestHelper';
|
import { AutorestHelper } from '../tools/autorestHelper';
|
||||||
import { createNewProjectFromDatabaseWithQuickpick } from '../dialogs/createProjectFromDatabaseQuickpick';
|
import { createNewProjectFromDatabaseWithQuickpick } from '../dialogs/createProjectFromDatabaseQuickpick';
|
||||||
import { addDatabaseReferenceQuickpick } from '../dialogs/addDatabaseReferenceQuickpick';
|
import { addDatabaseReferenceQuickpick } from '../dialogs/addDatabaseReferenceQuickpick';
|
||||||
import { IDeployProfile } from '../models/deploy/deployProfile';
|
import { ILocalDbDeployProfile, ISqlDbDeployProfile } from '../models/deploy/deployProfile';
|
||||||
import { EntryType, FileProjectEntry, IDatabaseReferenceProjectEntry, SqlProjectReferenceProjectEntry } from '../models/projectEntry';
|
import { EntryType, FileProjectEntry, IDatabaseReferenceProjectEntry, SqlProjectReferenceProjectEntry } from '../models/projectEntry';
|
||||||
import { UpdateProjectAction, UpdateProjectDataModel } from '../models/api/updateProject';
|
import { UpdateProjectAction, UpdateProjectDataModel } from '../models/api/updateProject';
|
||||||
import { targetPlatformToAssets } from '../projectProvider/projectAssets';
|
import { targetPlatformToAssets } from '../projectProvider/projectAssets';
|
||||||
|
import { AzureSqlClient } from '../models/deploy/azureSqlClient';
|
||||||
|
|
||||||
const maxTableLength = 10;
|
const maxTableLength = 10;
|
||||||
|
|
||||||
@@ -75,6 +76,7 @@ export class ProjectsController {
|
|||||||
private buildInfo: DashboardData[] = [];
|
private buildInfo: DashboardData[] = [];
|
||||||
private publishInfo: PublishData[] = [];
|
private publishInfo: PublishData[] = [];
|
||||||
private deployService: DeployService;
|
private deployService: DeployService;
|
||||||
|
private azureSqlClient: AzureSqlClient;
|
||||||
private autorestHelper: AutorestHelper;
|
private autorestHelper: AutorestHelper;
|
||||||
|
|
||||||
projFileWatchers = new Map<string, vscode.FileSystemWatcher>();
|
projFileWatchers = new Map<string, vscode.FileSystemWatcher>();
|
||||||
@@ -82,7 +84,8 @@ export class ProjectsController {
|
|||||||
constructor(private _outputChannel: vscode.OutputChannel) {
|
constructor(private _outputChannel: vscode.OutputChannel) {
|
||||||
this.netCoreTool = new NetCoreTool(this._outputChannel);
|
this.netCoreTool = new NetCoreTool(this._outputChannel);
|
||||||
this.buildHelper = new BuildHelper();
|
this.buildHelper = new BuildHelper();
|
||||||
this.deployService = new DeployService(this._outputChannel);
|
this.azureSqlClient = new AzureSqlClient();
|
||||||
|
this.deployService = new DeployService(this.azureSqlClient, this._outputChannel);
|
||||||
this.autorestHelper = new AutorestHelper(this._outputChannel);
|
this.autorestHelper = new AutorestHelper(this._outputChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,12 +290,47 @@ export class ProjectsController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publishes a project to a new Azure server
|
||||||
|
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project or the Project itself
|
||||||
|
* @param deployProfile deploy profile
|
||||||
|
*/
|
||||||
|
public async publishToNewAzureServer(context: Project | dataworkspace.WorkspaceTreeItem, deployProfile: ISqlDbDeployProfile): Promise<void> {
|
||||||
|
try {
|
||||||
|
TelemetryReporter.sendActionEvent(TelemetryViews.ProjectController, TelemetryActions.publishToNewAzureServer);
|
||||||
|
const project: Project = this.getProjectFromContext(context);
|
||||||
|
if (deployProfile?.deploySettings && deployProfile?.sqlDbSetting) {
|
||||||
|
void utils.showInfoMessageWithOutputChannel(constants.creatingAzureSqlServer(deployProfile?.sqlDbSetting?.serverName), this._outputChannel);
|
||||||
|
const connectionUri = await this.deployService.createNewAzureSqlServer(deployProfile);
|
||||||
|
if (connectionUri) {
|
||||||
|
deployProfile.deploySettings.connectionUri = connectionUri;
|
||||||
|
const publishResult = await this.publishOrScriptProject(project, deployProfile.deploySettings, true);
|
||||||
|
if (publishResult && publishResult.success) {
|
||||||
|
if (deployProfile.sqlDbSetting) {
|
||||||
|
|
||||||
|
// Connecting to the deployed db to add the profile to connection viewlet
|
||||||
|
await this.deployService.getConnection(deployProfile.sqlDbSetting, true, deployProfile.sqlDbSetting.dbName);
|
||||||
|
}
|
||||||
|
void vscode.window.showInformationMessage(constants.publishProjectSucceed);
|
||||||
|
} else {
|
||||||
|
void utils.showErrorMessageWithOutputChannel(constants.publishToNewAzureServerFailed, publishResult?.errorMessage || '', this._outputChannel);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
void utils.showErrorMessageWithOutputChannel(constants.publishToNewAzureServerFailed, constants.deployProjectFailedMessage, this._outputChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
void utils.showErrorMessageWithOutputChannel(constants.publishToNewAzureServerFailed, error, this._outputChannel);
|
||||||
|
TelemetryReporter.sendErrorEvent(TelemetryViews.ProjectController, TelemetryActions.publishToNewAzureServer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishes a project to docker container
|
* Publishes a project to docker container
|
||||||
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project or the Project itself
|
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project or the Project itself
|
||||||
* @param deployProfile
|
* @param deployProfile
|
||||||
*/
|
*/
|
||||||
public async publishToDockerContainer(context: Project | dataworkspace.WorkspaceTreeItem, deployProfile: IDeployProfile): Promise<void> {
|
public async publishToDockerContainer(context: Project | dataworkspace.WorkspaceTreeItem, deployProfile: ILocalDbDeployProfile): Promise<void> {
|
||||||
const project: Project = this.getProjectFromContext(context);
|
const project: Project = this.getProjectFromContext(context);
|
||||||
try {
|
try {
|
||||||
TelemetryReporter.sendActionEvent(TelemetryViews.ProjectController, TelemetryActions.publishToContainer);
|
TelemetryReporter.sendActionEvent(TelemetryViews.ProjectController, TelemetryActions.publishToContainer);
|
||||||
@@ -301,7 +339,7 @@ export class ProjectsController {
|
|||||||
let connectionUri: string | undefined;
|
let connectionUri: string | undefined;
|
||||||
if (deployProfile.localDbSetting) {
|
if (deployProfile.localDbSetting) {
|
||||||
void utils.showInfoMessageWithOutputChannel(constants.publishingProjectMessage, this._outputChannel);
|
void utils.showInfoMessageWithOutputChannel(constants.publishingProjectMessage, this._outputChannel);
|
||||||
connectionUri = await this.deployService.deploy(deployProfile, project);
|
connectionUri = await this.deployService.deployToContainer(deployProfile, project);
|
||||||
if (connectionUri) {
|
if (connectionUri) {
|
||||||
deployProfile.deploySettings.connectionUri = connectionUri;
|
deployProfile.deploySettings.connectionUri = connectionUri;
|
||||||
}
|
}
|
||||||
@@ -369,9 +407,19 @@ export class ProjectsController {
|
|||||||
|
|
||||||
if (publishTarget === constants.PublishTargetType.docker) {
|
if (publishTarget === constants.PublishTargetType.docker) {
|
||||||
const deployProfile = await launchPublishToDockerContainerQuickpick(project);
|
const deployProfile = await launchPublishToDockerContainerQuickpick(project);
|
||||||
if (deployProfile?.deploySettings) {
|
if (deployProfile?.deploySettings && deployProfile?.localDbSetting) {
|
||||||
await this.publishToDockerContainer(project, deployProfile);
|
await this.publishToDockerContainer(project, deployProfile);
|
||||||
}
|
}
|
||||||
|
} else if (publishTarget === constants.PublishTargetType.newAzureServer) {
|
||||||
|
try {
|
||||||
|
const settings = await launchCreateAzureServerQuickPick(project, this.azureSqlClient);
|
||||||
|
if (settings?.deploySettings && settings?.sqlDbSetting) {
|
||||||
|
await this.publishToNewAzureServer(project, settings);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
void utils.showErrorMessageWithOutputChannel(constants.publishToNewAzureServerFailed, error, this._outputChannel);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let settings: IDeploySettings | undefined = await getPublishDatabaseSettings(project);
|
let settings: IDeploySettings | undefined = await getPublishDatabaseSettings(project);
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,14 @@ import * as vscode from 'vscode';
|
|||||||
import * as constants from '../common/constants';
|
import * as constants from '../common/constants';
|
||||||
import * as utils from '../common/utils';
|
import * as utils from '../common/utils';
|
||||||
import * as uiUtils from './utils';
|
import * as uiUtils from './utils';
|
||||||
import { AppSettingType, DockerImageInfo, IDeployAppIntegrationProfile, IDeployProfile, ILocalDbSetting } from '../models/deploy/deployProfile';
|
import { AppSettingType, DockerImageInfo, IDeployAppIntegrationProfile, ISqlDbDeployProfile, ILocalDbDeployProfile, ILocalDbSetting } from '../models/deploy/deployProfile';
|
||||||
import { Project } from '../models/project';
|
import { Project } from '../models/project';
|
||||||
import { getPublishDatabaseSettings } from './publishDatabaseQuickpick';
|
import { getPublishDatabaseSettings } from './publishDatabaseQuickpick';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fse from 'fs-extra';
|
import * as fse from 'fs-extra';
|
||||||
|
import { AzureSqlClient } from '../models/deploy/azureSqlClient';
|
||||||
|
import { IDeploySettings } from '../models/IDeploySettings';
|
||||||
|
import { IAccount } from 'vscode-mssql';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create flow for Deploying a database using only VS Code-native APIs such as QuickPick
|
* Create flow for Deploying a database using only VS Code-native APIs such as QuickPick
|
||||||
@@ -112,11 +115,166 @@ async function launchEulaQuickPick(imageInfo: DockerImageInfo | undefined): Prom
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function launchCreateAzureServerQuickPick(project: Project, azureSqlClient: AzureSqlClient): Promise<ISqlDbDeployProfile | undefined> {
|
||||||
|
|
||||||
|
const name = uiUtils.getPublishServerName(project.getProjectTargetVersion());
|
||||||
|
const accounts = await azureSqlClient.getAccounts();
|
||||||
|
const accountOptions = accounts.map(x => x.displayInfo?.displayName || '');
|
||||||
|
accountOptions.unshift(constants.azureAddAccount);
|
||||||
|
|
||||||
|
let account: IAccount | undefined;
|
||||||
|
let accountOption = await vscode.window.showQuickPick(
|
||||||
|
accountOptions,
|
||||||
|
{ title: constants.azureAccounts, ignoreFocusOut: true });
|
||||||
|
|
||||||
|
// Return when user hits escape
|
||||||
|
if (!accountOption) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountOption === constants.azureAddAccount) {
|
||||||
|
account = await azureSqlClient.getAccount();
|
||||||
|
} else {
|
||||||
|
account = accounts.find(x => x.displayInfo.displayName === accountOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessions = await azureSqlClient.getSessions(account);
|
||||||
|
|
||||||
|
const subscriptionName = await vscode.window.showQuickPick(
|
||||||
|
sessions.map(x => x.subscription.displayName || ''),
|
||||||
|
{ title: constants.azureSubscription, ignoreFocusOut: true });
|
||||||
|
|
||||||
|
// Return when user hits escape
|
||||||
|
if (!subscriptionName) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const session = sessions.find(x => x.subscription.displayName === subscriptionName);
|
||||||
|
|
||||||
|
if (!session?.subscription?.subscriptionId) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resourceGroups = await azureSqlClient.getResourceGroups(session);
|
||||||
|
const resourceGroupName = await vscode.window.showQuickPick(
|
||||||
|
resourceGroups.map(x => x.name || ''),
|
||||||
|
{ title: constants.resourceGroup, ignoreFocusOut: true });
|
||||||
|
|
||||||
|
// Return when user hits escape
|
||||||
|
if (!resourceGroupName) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resourceGroup = resourceGroups.find(x => x.name === resourceGroupName);
|
||||||
|
|
||||||
|
// Return resource group is invalid
|
||||||
|
if (!resourceGroup) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let locations = await azureSqlClient.getLocations(session);
|
||||||
|
if (resourceGroup.location) {
|
||||||
|
const defaultLocation = locations.find(x => x.name === resourceGroup.location);
|
||||||
|
if (defaultLocation) {
|
||||||
|
locations = locations.filter(x => x.name !== defaultLocation.name);
|
||||||
|
locations.unshift(defaultLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let locationName = await vscode.window.showQuickPick(
|
||||||
|
locations.map(x => x.name || ''),
|
||||||
|
{ title: constants.azureLocation, ignoreFocusOut: true, placeHolder: resourceGroup?.location });
|
||||||
|
|
||||||
|
// Return when user hits escape
|
||||||
|
if (!locationName) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let serverName: string | undefined = '';
|
||||||
|
serverName = await vscode.window.showInputBox({
|
||||||
|
title: constants.azureServerName,
|
||||||
|
ignoreFocusOut: true,
|
||||||
|
value: serverName,
|
||||||
|
password: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return when user hits escape
|
||||||
|
if (!serverName) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let user: string | undefined = '';
|
||||||
|
user = await vscode.window.showInputBox({
|
||||||
|
title: constants.enterUser(name),
|
||||||
|
ignoreFocusOut: true,
|
||||||
|
value: user,
|
||||||
|
password: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return when user hits escape
|
||||||
|
if (!user) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let password: string | undefined = '';
|
||||||
|
password = await vscode.window.showInputBox({
|
||||||
|
title: constants.enterPassword(name),
|
||||||
|
ignoreFocusOut: true,
|
||||||
|
value: password,
|
||||||
|
validateInput: input => !utils.isValidSQLPassword(input) ? constants.invalidSQLPasswordMessage(name) : undefined,
|
||||||
|
password: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return when user hits escape
|
||||||
|
if (!password) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let confirmPassword: string | undefined = '';
|
||||||
|
confirmPassword = await vscode.window.showInputBox({
|
||||||
|
title: constants.confirmPassword(name),
|
||||||
|
ignoreFocusOut: true,
|
||||||
|
value: confirmPassword,
|
||||||
|
validateInput: input => input !== password ? constants.passwordNotMatch(name) : undefined,
|
||||||
|
password: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return when user hits escape
|
||||||
|
if (!confirmPassword) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let settings: IDeploySettings | undefined = await getPublishDatabaseSettings(project, false);
|
||||||
|
|
||||||
|
return {
|
||||||
|
// TODO add tenant
|
||||||
|
deploySettings: settings, sqlDbSetting: {
|
||||||
|
tenantId: session.tenantId,
|
||||||
|
accountId: session.account.key.id,
|
||||||
|
serverName: serverName,
|
||||||
|
userName: user,
|
||||||
|
password: password,
|
||||||
|
port: 1433,
|
||||||
|
dbName: '',
|
||||||
|
session: session,
|
||||||
|
resourceGroupName: resourceGroup.name || '',
|
||||||
|
location: locationName
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create flow for publishing a database to docker container using only VS Code-native APIs such as QuickPick
|
* Create flow for publishing a database to docker container using only VS Code-native APIs such as QuickPick
|
||||||
*/
|
*/
|
||||||
export async function launchPublishToDockerContainerQuickpick(project: Project): Promise<IDeployProfile | undefined> {
|
export async function launchPublishToDockerContainerQuickpick(project: Project): Promise<ILocalDbDeployProfile | undefined> {
|
||||||
|
|
||||||
const name = uiUtils.getPublishServerName(project.getProjectTargetVersion());
|
const name = uiUtils.getPublishServerName(project.getProjectTargetVersion());
|
||||||
let localDbSetting: ILocalDbSetting | undefined;
|
let localDbSetting: ILocalDbSetting | undefined;
|
||||||
// Deploy to docker selected
|
// Deploy to docker selected
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { IconPathHelper } from '../common/iconHelper';
|
|||||||
import { cssStyles } from '../common/uiConstants';
|
import { cssStyles } from '../common/uiConstants';
|
||||||
import { getAgreementDisplayText, getConnectionName, getDockerBaseImages, getPublishServerName } from './utils';
|
import { getAgreementDisplayText, getConnectionName, getDockerBaseImages, getPublishServerName } from './utils';
|
||||||
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
|
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
|
||||||
import { IDeployProfile } from '../models/deploy/deployProfile';
|
import { ILocalDbDeployProfile } from '../models/deploy/deployProfile';
|
||||||
import { Deferred } from '../common/promise';
|
import { Deferred } from '../common/promise';
|
||||||
|
|
||||||
interface DataSourceDropdownValue extends azdataType.CategoryValue {
|
interface DataSourceDropdownValue extends azdataType.CategoryValue {
|
||||||
@@ -62,7 +62,7 @@ export class PublishDatabaseDialog {
|
|||||||
private toDispose: vscode.Disposable[] = [];
|
private toDispose: vscode.Disposable[] = [];
|
||||||
|
|
||||||
public publish: ((proj: Project, profile: IDeploySettings) => any) | undefined;
|
public publish: ((proj: Project, profile: IDeploySettings) => any) | undefined;
|
||||||
public publishToContainer: ((proj: Project, profile: IDeployProfile) => any) | undefined;
|
public publishToContainer: ((proj: Project, profile: ILocalDbDeployProfile) => any) | undefined;
|
||||||
public generateScript: ((proj: Project, profile: IDeploySettings) => any) | undefined;
|
public generateScript: ((proj: Project, profile: IDeploySettings) => any) | undefined;
|
||||||
public readPublishProfile: ((profileUri: vscode.Uri) => any) | undefined;
|
public readPublishProfile: ((profileUri: vscode.Uri) => any) | undefined;
|
||||||
|
|
||||||
@@ -232,7 +232,7 @@ export class PublishDatabaseDialog {
|
|||||||
const dockerBaseImage = this.getBaseDockerImageName();
|
const dockerBaseImage = this.getBaseDockerImageName();
|
||||||
const baseImages = getDockerBaseImages(this.project.getProjectTargetVersion());
|
const baseImages = getDockerBaseImages(this.project.getProjectTargetVersion());
|
||||||
const imageInfo = baseImages.find(x => x.name === dockerBaseImage);
|
const imageInfo = baseImages.find(x => x.name === dockerBaseImage);
|
||||||
const settings: IDeployProfile = {
|
const settings: ILocalDbDeployProfile = {
|
||||||
localDbSetting: {
|
localDbSetting: {
|
||||||
dbName: this.targetDatabaseName,
|
dbName: this.targetDatabaseName,
|
||||||
dockerBaseImage: dockerBaseImage,
|
dockerBaseImage: dockerBaseImage,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { getDefaultPublishDeploymentOptions, getVscodeMssqlApi } from '../common
|
|||||||
import { IConnectionInfo } from 'vscode-mssql';
|
import { IConnectionInfo } from 'vscode-mssql';
|
||||||
import { IDeploySettings } from '../models/IDeploySettings';
|
import { IDeploySettings } from '../models/IDeploySettings';
|
||||||
import { getPublishServerName } from './utils';
|
import { getPublishServerName } from './utils';
|
||||||
|
import { SqlTargetPlatform } from 'sqldbproj';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create flow for Publishing a database using only VS Code-native APIs such as QuickPick
|
* Create flow for Publishing a database using only VS Code-native APIs such as QuickPick
|
||||||
@@ -209,9 +210,14 @@ export async function getPublishDatabaseSettings(project: Project, promptForConn
|
|||||||
|
|
||||||
export async function launchPublishTargetOption(project: Project): Promise<constants.PublishTargetType | undefined> {
|
export async function launchPublishTargetOption(project: Project): Promise<constants.PublishTargetType | undefined> {
|
||||||
// Show options to user for deploy to existing server or docker
|
// Show options to user for deploy to existing server or docker
|
||||||
const name = getPublishServerName(project.getProjectTargetVersion());
|
const target = project.getProjectTargetVersion();
|
||||||
|
const name = getPublishServerName(target);
|
||||||
|
const logicalServerName = target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure) ? constants.AzureSqlLogicalServerName : constants.SqlServerName;
|
||||||
|
const options = target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure) ?
|
||||||
|
[constants.publishToDockerContainer(name), constants.publishToNewAzureServer, constants.publishToExistingServer(logicalServerName)] :
|
||||||
|
[constants.publishToDockerContainer(name), constants.publishToExistingServer(logicalServerName)];
|
||||||
const publishOption = await vscode.window.showQuickPick(
|
const publishOption = await vscode.window.showQuickPick(
|
||||||
[constants.publishToExistingServer(name), constants.publishToDockerContainer(name)],
|
options,
|
||||||
{ title: constants.selectPublishOption, ignoreFocusOut: true });
|
{ title: constants.selectPublishOption, ignoreFocusOut: true });
|
||||||
|
|
||||||
// Return when user hits escape
|
// Return when user hits escape
|
||||||
@@ -224,6 +230,8 @@ export async function launchPublishTargetOption(project: Project): Promise<const
|
|||||||
return constants.PublishTargetType.existingServer;
|
return constants.PublishTargetType.existingServer;
|
||||||
case constants.publishToDockerContainer(name):
|
case constants.publishToDockerContainer(name):
|
||||||
return constants.PublishTargetType.docker;
|
return constants.PublishTargetType.docker;
|
||||||
|
case constants.publishToNewAzureServer:
|
||||||
|
return constants.PublishTargetType.newAzureServer;
|
||||||
default:
|
default:
|
||||||
return constants.PublishTargetType.existingServer;
|
return constants.PublishTargetType.existingServer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as utils from '../../common/utils';
|
||||||
|
import { IAccount, IAzureAccountSession, azure } from 'vscode-mssql';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client module to call Azure APIs for getting or creating resources
|
||||||
|
*/
|
||||||
|
export class AzureSqlClient {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private _azureAccountServiceFactory: utils.AzureAccountServiceFactory = utils.defaultAzureAccountServiceFactory,
|
||||||
|
private _azureResourceServiceFactory: utils.AzureResourceServiceFactory = utils.defaultAzureResourceServiceFactory
|
||||||
|
) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns existing Azure accounts
|
||||||
|
*/
|
||||||
|
public async getAccounts(): Promise<IAccount[]> {
|
||||||
|
const azureAccountService = await this._azureAccountServiceFactory();
|
||||||
|
return await azureAccountService.getAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompt user to login to Azure and returns the account
|
||||||
|
* @returns Azure account that user logged in to
|
||||||
|
*/
|
||||||
|
public async getAccount(): Promise<IAccount> {
|
||||||
|
const azureAccountService = await this._azureAccountServiceFactory();
|
||||||
|
return await azureAccountService.addAccount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Azure locations for given subscription
|
||||||
|
*/
|
||||||
|
public async getLocations(session: IAzureAccountSession): Promise<azure.subscription.Location[]> {
|
||||||
|
const azureResourceService = await this._azureResourceServiceFactory();
|
||||||
|
return await azureResourceService.getLocations(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Azure sessions with subscription, tenant and token for given account
|
||||||
|
*/
|
||||||
|
public async getSessions(account: IAccount): Promise<IAzureAccountSession[]> {
|
||||||
|
const azureAccountService = await this._azureAccountServiceFactory();
|
||||||
|
return await azureAccountService.getAccountSessions(account);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Azure SQL server for given subscription, resource group and location
|
||||||
|
*/
|
||||||
|
public async createOrUpdateServer(session: IAzureAccountSession, resourceGroupName: string, serverName: string, parameters: azure.sql.Server): Promise<string | undefined> {
|
||||||
|
const azureResourceService = await this._azureResourceServiceFactory();
|
||||||
|
return await azureResourceService.createOrUpdateServer(session, resourceGroupName, serverName, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Azure resource groups for given subscription
|
||||||
|
*/
|
||||||
|
public async getResourceGroups(session: IAzureAccountSession): Promise<Array<azure.resources.ResourceGroup> | []> {
|
||||||
|
const azureResourceService = await this._azureResourceServiceFactory();
|
||||||
|
return await azureResourceService.getResourceGroups(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,32 +5,49 @@
|
|||||||
|
|
||||||
import { IDeploySettings } from '../IDeploySettings';
|
import { IDeploySettings } from '../IDeploySettings';
|
||||||
import type * as azdataType from 'azdata';
|
import type * as azdataType from 'azdata';
|
||||||
|
import { IAzureAccountSession } from 'vscode-mssql';
|
||||||
|
|
||||||
export enum AppSettingType {
|
export enum AppSettingType {
|
||||||
None,
|
None,
|
||||||
AzureFunction
|
AzureFunction
|
||||||
}
|
}
|
||||||
export interface IDeployProfile {
|
export interface ILocalDbDeployProfile {
|
||||||
localDbSetting?: ILocalDbSetting;
|
localDbSetting?: ILocalDbSetting;
|
||||||
deploySettings?: IDeploySettings;
|
deploySettings?: IDeploySettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ISqlDbDeployProfile {
|
||||||
|
sqlDbSetting?: ISqlDbSetting;
|
||||||
|
deploySettings?: IDeploySettings;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IDeployAppIntegrationProfile {
|
export interface IDeployAppIntegrationProfile {
|
||||||
envVariableName?: string;
|
envVariableName?: string;
|
||||||
appSettingFile?: string;
|
appSettingFile?: string;
|
||||||
appSettingType: AppSettingType;
|
appSettingType: AppSettingType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILocalDbSetting {
|
export interface ISqlDbSetting extends ISqlConnectionProperties {
|
||||||
serverName: string,
|
session: IAzureAccountSession
|
||||||
port: number,
|
resourceGroupName: string,
|
||||||
userName: string,
|
location: string
|
||||||
password: string,
|
}
|
||||||
dbName: string,
|
|
||||||
|
export interface ILocalDbSetting extends ISqlConnectionProperties {
|
||||||
dockerBaseImage: string,
|
dockerBaseImage: string,
|
||||||
dockerBaseImageEula: string,
|
dockerBaseImageEula: string,
|
||||||
connectionRetryTimeout?: number,
|
}
|
||||||
profileName?: string
|
|
||||||
|
export interface ISqlConnectionProperties {
|
||||||
|
tenantId?: string,
|
||||||
|
accountId?: string
|
||||||
|
serverName: string,
|
||||||
|
userName: string,
|
||||||
|
password: string,
|
||||||
|
port: number,
|
||||||
|
dbName: string,
|
||||||
|
profileName?: string,
|
||||||
|
connectionRetryTimeout?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DockerImageInfo {
|
export interface DockerImageInfo {
|
||||||
@@ -41,3 +58,4 @@ export interface DockerImageInfo {
|
|||||||
export interface AgreementInfo {
|
export interface AgreementInfo {
|
||||||
link: azdataType.LinkArea;
|
link: azdataType.LinkArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { AppSettingType, IDeployAppIntegrationProfile, IDeployProfile, ILocalDbSetting } from './deployProfile';
|
import { AppSettingType, IDeployAppIntegrationProfile, ILocalDbDeployProfile, ILocalDbSetting, ISqlConnectionProperties, ISqlDbDeployProfile } from './deployProfile';
|
||||||
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||||
import { Project } from '../project';
|
import { Project } from '../project';
|
||||||
import * as constants from '../../common/constants';
|
import * as constants from '../../common/constants';
|
||||||
@@ -13,6 +13,8 @@ import * as vscode from 'vscode';
|
|||||||
import { ConnectionResult } from 'azdata';
|
import { ConnectionResult } from 'azdata';
|
||||||
import * as templates from '../../templates/templates';
|
import * as templates from '../../templates/templates';
|
||||||
import { ShellExecutionHelper } from '../../tools/shellExecutionHelper';
|
import { ShellExecutionHelper } from '../../tools/shellExecutionHelper';
|
||||||
|
import { AzureSqlClient } from './azureSqlClient';
|
||||||
|
import { IFireWallRuleError } from 'vscode-mssql';
|
||||||
|
|
||||||
interface DockerImageSpec {
|
interface DockerImageSpec {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -21,7 +23,7 @@ interface DockerImageSpec {
|
|||||||
}
|
}
|
||||||
export class DeployService {
|
export class DeployService {
|
||||||
|
|
||||||
constructor(private _outputChannel: vscode.OutputChannel, shellExecutionHelper: ShellExecutionHelper | undefined = undefined) {
|
constructor(private _azureSqlClient = new AzureSqlClient(), private _outputChannel: vscode.OutputChannel, shellExecutionHelper: ShellExecutionHelper | undefined = undefined) {
|
||||||
this._shellExecutionHelper = shellExecutionHelper ?? new ShellExecutionHelper(this._outputChannel);
|
this._shellExecutionHelper = shellExecutionHelper ?? new ShellExecutionHelper(this._outputChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +52,7 @@ export class DeployService {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateAppSettings(profile: IDeployAppIntegrationProfile, deployProfile: IDeployProfile | undefined): Promise<void> {
|
public async updateAppSettings(profile: IDeployAppIntegrationProfile, deployProfile: ILocalDbDeployProfile | undefined): Promise<void> {
|
||||||
// Update app settings
|
// Update app settings
|
||||||
//
|
//
|
||||||
if (!profile.appSettingFile) {
|
if (!profile.appSettingFile) {
|
||||||
@@ -122,7 +124,37 @@ export class DeployService {
|
|||||||
return { label: imageLabel, tag: imageTag, containerName: dockerName };
|
return { label: imageLabel, tag: imageTag, containerName: dockerName };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async deploy(profile: IDeployProfile, project: Project): Promise<string | undefined> {
|
/**
|
||||||
|
* Creates a new Azure Sql server and tries to connect to the new server. If connection fails because of firewall rule, it prompts user to add firewall rule settings
|
||||||
|
* @param profile Azure Sql server settings
|
||||||
|
* @returns connection url for the new server
|
||||||
|
*/
|
||||||
|
public async createNewAzureSqlServer(profile: ISqlDbDeployProfile | undefined): Promise<string | undefined> {
|
||||||
|
if (!profile?.sqlDbSetting) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logToOutput(constants.creatingAzureSqlServer(profile?.sqlDbSetting?.serverName));
|
||||||
|
|
||||||
|
// Create the server
|
||||||
|
const server = await this._azureSqlClient.createOrUpdateServer(profile.sqlDbSetting.session, profile?.sqlDbSetting.resourceGroupName, profile?.sqlDbSetting.serverName, {
|
||||||
|
location: profile?.sqlDbSetting?.location,
|
||||||
|
administratorLogin: profile?.sqlDbSetting.userName,
|
||||||
|
administratorLoginPassword: profile?.sqlDbSetting.password
|
||||||
|
});
|
||||||
|
if (server) {
|
||||||
|
this._outputChannel.appendLine(constants.serverCreated);
|
||||||
|
profile.sqlDbSetting.serverName = server;
|
||||||
|
|
||||||
|
this.logToOutput(constants.azureSqlServerCreated(profile?.sqlDbSetting?.serverName));
|
||||||
|
|
||||||
|
// Connect to the server
|
||||||
|
return await this.getConnection(profile.sqlDbSetting, false, constants.master);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deployToContainer(profile: ILocalDbDeployProfile, project: Project): Promise<string | undefined> {
|
||||||
return await this.executeTask(constants.deployDbTaskName, async () => {
|
return await this.executeTask(constants.deployDbTaskName, async () => {
|
||||||
if (!profile.localDbSetting) {
|
if (!profile.localDbSetting) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -218,7 +250,7 @@ export class DeployService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Connects to a database
|
// Connects to a database
|
||||||
private async connectToDatabase(profile: ILocalDbSetting, saveConnectionAndPassword: boolean, database: string): Promise<ConnectionResult | string | undefined> {
|
private async connectToDatabase(profile: ISqlConnectionProperties, saveConnectionAndPassword: boolean, database: string): Promise<ConnectionResult | string | undefined> {
|
||||||
const getAzdataApi = await utils.getAzdataApi();
|
const getAzdataApi = await utils.getAzdataApi();
|
||||||
const vscodeMssqlApi = getAzdataApi ? undefined : await utils.getVscodeMssqlApi();
|
const vscodeMssqlApi = getAzdataApi ? undefined : await utils.getVscodeMssqlApi();
|
||||||
if (getAzdataApi) {
|
if (getAzdataApi) {
|
||||||
@@ -248,7 +280,7 @@ export class DeployService {
|
|||||||
encrypt: false,
|
encrypt: false,
|
||||||
connectTimeout: 30,
|
connectTimeout: 30,
|
||||||
applicationName: 'SQL Database Project',
|
applicationName: 'SQL Database Project',
|
||||||
accountId: undefined,
|
accountId: profile.accountId,
|
||||||
azureAccountToken: undefined,
|
azureAccountToken: undefined,
|
||||||
applicationIntent: undefined,
|
applicationIntent: undefined,
|
||||||
attachDbFilename: undefined,
|
attachDbFilename: undefined,
|
||||||
@@ -272,9 +304,19 @@ export class DeployService {
|
|||||||
workstationId: undefined,
|
workstationId: undefined,
|
||||||
profileName: profile.profileName,
|
profileName: profile.profileName,
|
||||||
expiresOn: undefined,
|
expiresOn: undefined,
|
||||||
tenantId: undefined
|
tenantId: profile.tenantId
|
||||||
};
|
};
|
||||||
let connectionUrl = await vscodeMssqlApi.connect(connectionProfile, saveConnectionAndPassword);
|
let connectionUrl = '';
|
||||||
|
try {
|
||||||
|
connectionUrl = await vscodeMssqlApi.connect(connectionProfile, saveConnectionAndPassword);
|
||||||
|
} catch (err) {
|
||||||
|
const firewallRuleError = <IFireWallRuleError>err;
|
||||||
|
if (firewallRuleError?.connectionUri) {
|
||||||
|
await vscodeMssqlApi.promptForFirewallRule(err.connectionUri, connectionProfile);
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
return connectionUrl;
|
return connectionUrl;
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -307,7 +349,7 @@ export class DeployService {
|
|||||||
return connectionResult ? connectionResult.connectionId : <string>connection;
|
return connectionResult ? connectionResult.connectionId : <string>connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getConnection(profile: ILocalDbSetting, saveConnectionAndPassword: boolean, database: string): Promise<string | undefined> {
|
public async getConnection(profile: ISqlConnectionProperties, saveConnectionAndPassword: boolean, database: string): Promise<string | undefined> {
|
||||||
const getAzdataApi = await utils.getAzdataApi();
|
const getAzdataApi = await utils.getAzdataApi();
|
||||||
let connection = await utils.retry(
|
let connection = await utils.retry(
|
||||||
constants.connectingToSqlServerMessage,
|
constants.connectingToSqlServerMessage,
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as should from 'should';
|
||||||
|
import { AzureSqlClient } from '../../models/deploy/azureSqlClient';
|
||||||
|
import { IAccount, IAzureAccountService, IAzureAccountSession, IAzureResourceService, azure } from 'vscode-mssql';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export interface TestContext {
|
||||||
|
azureAccountService: IAzureAccountService;
|
||||||
|
azureResourceService: IAzureResourceService;
|
||||||
|
accounts: IAccount[];
|
||||||
|
session: IAzureAccountSession;
|
||||||
|
subscriptions: azure.subscription.Subscription[];
|
||||||
|
locations: azure.subscription.Location[];
|
||||||
|
groups: azure.resources.ResourceGroup[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createContext(): TestContext {
|
||||||
|
const accounts = [{
|
||||||
|
key: undefined!,
|
||||||
|
displayInfo: undefined!,
|
||||||
|
properties: {
|
||||||
|
tenants: [{
|
||||||
|
id: '',
|
||||||
|
displayName: ''
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
isStale: false,
|
||||||
|
isSignedIn: true
|
||||||
|
}];
|
||||||
|
const subscriptions: azure.subscription.Subscription[] = [{ subscriptionId: 'id1' }, { subscriptionId: 'id2' }];
|
||||||
|
const locations: azure.subscription.Location[] = [{ id: 'id1' }, { id: 'id2' }];
|
||||||
|
const groups: azure.resources.ResourceGroup[] = [{ id: 'id1', location: 'l1' }, { id: 'id2', location: 'l2' }];
|
||||||
|
const session: IAzureAccountSession = {
|
||||||
|
account: accounts[0],
|
||||||
|
subscription: subscriptions[0],
|
||||||
|
tenantId: 'tenantId',
|
||||||
|
token: {
|
||||||
|
key: '',
|
||||||
|
token: '',
|
||||||
|
tokenType: '',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
groups: groups,
|
||||||
|
locations: locations,
|
||||||
|
subscriptions: subscriptions,
|
||||||
|
session: session,
|
||||||
|
accounts: accounts,
|
||||||
|
azureAccountService: {
|
||||||
|
addAccount: () => Promise.resolve(accounts[0]),
|
||||||
|
getAccounts: () => Promise.resolve(accounts),
|
||||||
|
getAccountSecurityToken: () => Promise.resolve({
|
||||||
|
key: '',
|
||||||
|
token: '',
|
||||||
|
tokenType: ''
|
||||||
|
}),
|
||||||
|
getAccountSessions: () => Promise.resolve([session])
|
||||||
|
},
|
||||||
|
azureResourceService: {
|
||||||
|
getLocations: () => Promise.resolve(locations),
|
||||||
|
getResourceGroups: () => Promise.resolve(groups),
|
||||||
|
createOrUpdateServer: () => Promise.resolve('new_server')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Azure SQL client', function (): void {
|
||||||
|
|
||||||
|
it('Should return accounts successfully', async function (): Promise<void> {
|
||||||
|
const testContext = createContext();
|
||||||
|
const azureSqlClient = new AzureSqlClient(() => Promise.resolve(testContext.azureAccountService));
|
||||||
|
const accounts = await azureSqlClient.getAccounts();
|
||||||
|
should(accounts.length).equal(testContext.accounts.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should create and return new account successfully', async function (): Promise<void> {
|
||||||
|
const testContext = createContext();
|
||||||
|
const azureSqlClient = new AzureSqlClient(() => Promise.resolve(testContext.azureAccountService));
|
||||||
|
const account = await azureSqlClient.getAccount();
|
||||||
|
should(account.key).equal(testContext.accounts[0].key);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should return subscriptions successfully', async function (): Promise<void> {
|
||||||
|
const testContext = createContext();
|
||||||
|
const azureSqlClient = new AzureSqlClient(() => Promise.resolve(testContext.azureAccountService));
|
||||||
|
const result = await azureSqlClient.getSessions(testContext.accounts[0]);
|
||||||
|
should(result[0].subscription.id).deepEqual(testContext.subscriptions[0].id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should return locations successfully', async function (): Promise<void> {
|
||||||
|
const testContext = createContext();
|
||||||
|
const azureSqlClient = new AzureSqlClient(() => Promise.resolve(testContext.azureAccountService), () => Promise.resolve(testContext.azureResourceService));
|
||||||
|
const result = await azureSqlClient.getLocations(testContext.session);
|
||||||
|
should(result.length).deepEqual(testContext.locations.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should return resource groups successfully', async function (): Promise<void> {
|
||||||
|
const testContext = createContext();
|
||||||
|
const azureSqlClient = new AzureSqlClient(() => Promise.resolve(testContext.azureAccountService), () => Promise.resolve(testContext.azureResourceService));
|
||||||
|
const result = await azureSqlClient.getResourceGroups(testContext.session);
|
||||||
|
should(result.length).deepEqual(testContext.groups.length);
|
||||||
|
should(result[0].location).deepEqual(testContext.groups[0].location);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -11,16 +11,18 @@ import { DeployService } from '../../models/deploy/deployService';
|
|||||||
import { Project } from '../../models/project';
|
import { Project } from '../../models/project';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { AppSettingType, IDeployProfile } from '../../models/deploy/deployProfile';
|
import { AppSettingType, ILocalDbDeployProfile, ISqlDbDeployProfile } from '../../models/deploy/deployProfile';
|
||||||
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||||
import * as fse from 'fs-extra';
|
import * as fse from 'fs-extra';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as constants from '../../common/constants';
|
import * as constants from '../../common/constants';
|
||||||
import { ShellExecutionHelper } from '../../tools/shellExecutionHelper';
|
import { ShellExecutionHelper } from '../../tools/shellExecutionHelper';
|
||||||
import * as TypeMoq from 'typemoq';
|
import * as TypeMoq from 'typemoq';
|
||||||
|
import { AzureSqlClient } from '../../models/deploy/azureSqlClient';
|
||||||
|
|
||||||
export interface TestContext {
|
export interface TestContext {
|
||||||
outputChannel: vscode.OutputChannel;
|
outputChannel: vscode.OutputChannel;
|
||||||
|
azureSqlClient: TypeMoq.IMock<AzureSqlClient>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mockConnectionResult: azdata.ConnectionResult = {
|
export const mockConnectionResult: azdata.ConnectionResult = {
|
||||||
@@ -47,7 +49,8 @@ export function createContext(): TestContext {
|
|||||||
show: () => { },
|
show: () => { },
|
||||||
hide: () => { },
|
hide: () => { },
|
||||||
dispose: () => { }
|
dispose: () => { }
|
||||||
}
|
},
|
||||||
|
azureSqlClient: TypeMoq.Mock.ofType(AzureSqlClient)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +71,7 @@ describe('deploy service', function (): void {
|
|||||||
|
|
||||||
it('Should deploy a database to docker container successfully', async function (): Promise<void> {
|
it('Should deploy a database to docker container successfully', async function (): Promise<void> {
|
||||||
const testContext = createContext();
|
const testContext = createContext();
|
||||||
const deployProfile: IDeployProfile = {
|
const deployProfile: ILocalDbDeployProfile = {
|
||||||
localDbSetting: {
|
localDbSetting: {
|
||||||
dbName: 'test',
|
dbName: 'test',
|
||||||
password: 'PLACEHOLDER',
|
password: 'PLACEHOLDER',
|
||||||
@@ -85,20 +88,20 @@ describe('deploy service', function (): void {
|
|||||||
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
||||||
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
||||||
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
||||||
const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object);
|
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object);
|
||||||
sandbox.stub(azdata.connection, 'connect').returns(Promise.resolve(mockConnectionResult));
|
sandbox.stub(azdata.connection, 'connect').returns(Promise.resolve(mockConnectionResult));
|
||||||
sandbox.stub(azdata.connection, 'getUriForConnection').returns(Promise.resolve('connection'));
|
sandbox.stub(azdata.connection, 'getUriForConnection').returns(Promise.resolve('connection'));
|
||||||
sandbox.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve(constants.yesString));
|
sandbox.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve(constants.yesString));
|
||||||
sandbox.stub(azdata.tasks, 'startBackgroundOperation').callThrough();
|
sandbox.stub(azdata.tasks, 'startBackgroundOperation').callThrough();
|
||||||
|
|
||||||
let connection = await deployService.deploy(deployProfile, project1);
|
let connection = await deployService.deployToContainer(deployProfile, project1);
|
||||||
should(connection).equals('connection');
|
should(connection).equals('connection');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should fail the deploy if docker is not running', async function (): Promise<void> {
|
it('Should fail the deploy if docker is not running', async function (): Promise<void> {
|
||||||
const testContext = createContext();
|
const testContext = createContext();
|
||||||
const deployProfile: IDeployProfile = {
|
const deployProfile: ILocalDbDeployProfile = {
|
||||||
localDbSetting: {
|
localDbSetting: {
|
||||||
dbName: 'test',
|
dbName: 'test',
|
||||||
password: 'PLACEHOLDER',
|
password: 'PLACEHOLDER',
|
||||||
@@ -115,10 +118,10 @@ describe('deploy service', function (): void {
|
|||||||
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
||||||
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
||||||
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.reject('error'));
|
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.reject('error'));
|
||||||
const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object);
|
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object);
|
||||||
sandbox.stub(azdata.tasks, 'startBackgroundOperation').callThrough();
|
sandbox.stub(azdata.tasks, 'startBackgroundOperation').callThrough();
|
||||||
|
|
||||||
await should(deployService.deploy(deployProfile, project1)).rejected();
|
await should(deployService.deployToContainer(deployProfile, project1)).rejected();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should retry connecting to the server', async function (): Promise<void> {
|
it('Should retry connecting to the server', async function (): Promise<void> {
|
||||||
@@ -137,7 +140,7 @@ describe('deploy service', function (): void {
|
|||||||
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
||||||
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
||||||
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
||||||
const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object);
|
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object);
|
||||||
let connectionStub = sandbox.stub(azdata.connection, 'connect');
|
let connectionStub = sandbox.stub(azdata.connection, 'connect');
|
||||||
connectionStub.onFirstCall().returns(Promise.resolve(mockFailedConnectionResult));
|
connectionStub.onFirstCall().returns(Promise.resolve(mockFailedConnectionResult));
|
||||||
connectionStub.onSecondCall().returns(Promise.resolve(mockConnectionResult));
|
connectionStub.onSecondCall().returns(Promise.resolve(mockConnectionResult));
|
||||||
@@ -173,7 +176,7 @@ describe('deploy service', function (): void {
|
|||||||
const filePath = path.join(project1.projectFolderPath, 'local.settings.json');
|
const filePath = path.join(project1.projectFolderPath, 'local.settings.json');
|
||||||
await fse.writeFile(filePath, settingContent);
|
await fse.writeFile(filePath, settingContent);
|
||||||
|
|
||||||
const deployProfile: IDeployProfile = {
|
const deployProfile: ILocalDbDeployProfile = {
|
||||||
localDbSetting: {
|
localDbSetting: {
|
||||||
dbName: 'test',
|
dbName: 'test',
|
||||||
password: 'PLACEHOLDER',
|
password: 'PLACEHOLDER',
|
||||||
@@ -195,7 +198,7 @@ describe('deploy service', function (): void {
|
|||||||
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
||||||
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
||||||
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
||||||
const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object);
|
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object);
|
||||||
|
|
||||||
await deployService.updateAppSettings(appInteg, deployProfile);
|
await deployService.updateAppSettings(appInteg, deployProfile);
|
||||||
let newContent = JSON.parse(fse.readFileSync(filePath, 'utf8'));
|
let newContent = JSON.parse(fse.readFileSync(filePath, 'utf8'));
|
||||||
@@ -228,7 +231,7 @@ describe('deploy service', function (): void {
|
|||||||
const filePath = path.join(project1.projectFolderPath, 'local.settings.json');
|
const filePath = path.join(project1.projectFolderPath, 'local.settings.json');
|
||||||
await fse.writeFile(filePath, settingContent);
|
await fse.writeFile(filePath, settingContent);
|
||||||
|
|
||||||
const deployProfile: IDeployProfile = {
|
const deployProfile: ILocalDbDeployProfile = {
|
||||||
|
|
||||||
deploySettings: {
|
deploySettings: {
|
||||||
connectionUri: 'connection',
|
connectionUri: 'connection',
|
||||||
@@ -246,7 +249,7 @@ describe('deploy service', function (): void {
|
|||||||
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
||||||
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
||||||
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
||||||
const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object);
|
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object);
|
||||||
let connection = new azdata.connection.ConnectionProfile();
|
let connection = new azdata.connection.ConnectionProfile();
|
||||||
sandbox.stub(azdata.connection, 'getConnection').returns(Promise.resolve(connection));
|
sandbox.stub(azdata.connection, 'getConnection').returns(Promise.resolve(connection));
|
||||||
|
|
||||||
@@ -263,7 +266,7 @@ describe('deploy service', function (): void {
|
|||||||
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(`id
|
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(`id
|
||||||
id2
|
id2
|
||||||
id3`));
|
id3`));
|
||||||
const deployService = new DeployService(testContext.outputChannel, shellExecutionHelper.object);
|
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object);
|
||||||
const ids = await deployService.getCurrentDockerContainer('label');
|
const ids = await deployService.getCurrentDockerContainer('label');
|
||||||
await deployService.cleanDockerObjects(ids, ['docker stop', 'docker rm']);
|
await deployService.cleanDockerObjects(ids, ['docker stop', 'docker rm']);
|
||||||
shellExecutionHelper.verify(x => x.runStreamedCommand(TypeMoq.It.isAny(), undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(7));
|
shellExecutionHelper.verify(x => x.runStreamedCommand(TypeMoq.It.isAny(), undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(7));
|
||||||
@@ -271,7 +274,7 @@ describe('deploy service', function (): void {
|
|||||||
|
|
||||||
it('Should create docker image info correctly', () => {
|
it('Should create docker image info correctly', () => {
|
||||||
const testContext = createContext();
|
const testContext = createContext();
|
||||||
const deployService = new DeployService(testContext.outputChannel);
|
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel);
|
||||||
const id = UUID.generateUuid().toLocaleLowerCase();
|
const id = UUID.generateUuid().toLocaleLowerCase();
|
||||||
const baseImage = 'baseImage:latest';
|
const baseImage = 'baseImage:latest';
|
||||||
const tag = baseImage.replace(':', '-').replace(constants.sqlServerDockerRegistry, '').replace(/[^a-zA-Z0-9_,\-]/g, '').toLocaleLowerCase();
|
const tag = baseImage.replace(':', '-').replace(constants.sqlServerDockerRegistry, '').replace(/[^a-zA-Z0-9_,\-]/g, '').toLocaleLowerCase();
|
||||||
@@ -311,4 +314,53 @@ describe('deploy service', function (): void {
|
|||||||
tag: `${constants.dockerImageNamePrefix}-${imageProjectName}-${tag}`
|
tag: `${constants.dockerImageNamePrefix}-${imageProjectName}-${tag}`
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should create a new Azure SQL server successfully', async function (): Promise<void> {
|
||||||
|
const testContext = createContext();
|
||||||
|
const deployProfile: ISqlDbDeployProfile = {
|
||||||
|
sqlDbSetting: {
|
||||||
|
dbName: 'test',
|
||||||
|
password: 'PLACEHOLDER',
|
||||||
|
port: 1433,
|
||||||
|
serverName: 'localhost',
|
||||||
|
userName: 'sa',
|
||||||
|
connectionRetryTimeout: 1,
|
||||||
|
resourceGroupName: 'resourceGroups',
|
||||||
|
session: {
|
||||||
|
subscription: {
|
||||||
|
subscriptionId: 'subscriptionId',
|
||||||
|
},token: {
|
||||||
|
key: '',
|
||||||
|
token: '',
|
||||||
|
tokenType: '',
|
||||||
|
},
|
||||||
|
tenantId: '',
|
||||||
|
account: undefined!
|
||||||
|
},
|
||||||
|
location: 'location'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const fullyQualifiedDomainName = 'servername';
|
||||||
|
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
||||||
|
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
||||||
|
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
||||||
|
const session = deployProfile?.sqlDbSetting?.session;
|
||||||
|
if (deployProfile?.sqlDbSetting?.session && session) {
|
||||||
|
testContext.azureSqlClient.setup(x => x.createOrUpdateServer(
|
||||||
|
session,
|
||||||
|
deployProfile.sqlDbSetting?.resourceGroupName || '',
|
||||||
|
deployProfile.sqlDbSetting?.serverName || '',
|
||||||
|
{
|
||||||
|
location: deployProfile?.sqlDbSetting?.location || '',
|
||||||
|
administratorLogin: deployProfile?.sqlDbSetting?.userName,
|
||||||
|
administratorLoginPassword: deployProfile?.sqlDbSetting?.password
|
||||||
|
})).returns(() => Promise.resolve(fullyQualifiedDomainName));
|
||||||
|
}
|
||||||
|
sandbox.stub(azdata.connection, 'connect').returns(Promise.resolve(mockConnectionResult));
|
||||||
|
sandbox.stub(azdata.connection, 'getUriForConnection').returns(Promise.resolve('connection'));
|
||||||
|
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object);
|
||||||
|
let connection = await deployService.createNewAzureSqlServer(deployProfile);
|
||||||
|
should(deployProfile.sqlDbSetting?.serverName).equal(fullyQualifiedDomainName);
|
||||||
|
should(connection).equals('connection');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { ProjectsController } from '../../controllers/projectController';
|
|||||||
import { IDeploySettings } from '../../models/IDeploySettings';
|
import { IDeploySettings } from '../../models/IDeploySettings';
|
||||||
import { emptySqlDatabaseProjectTypeId } from '../../common/constants';
|
import { emptySqlDatabaseProjectTypeId } from '../../common/constants';
|
||||||
import { createContext, mockDacFxOptionsResult, TestContext } from '../testContext';
|
import { createContext, mockDacFxOptionsResult, TestContext } from '../testContext';
|
||||||
import { IDeployProfile } from '../../models/deploy/deployProfile';
|
import { ILocalDbDeployProfile } from '../../models/deploy/deployProfile';
|
||||||
|
|
||||||
let testContext: TestContext;
|
let testContext: TestContext;
|
||||||
describe('Publish Database Dialog', () => {
|
describe('Publish Database Dialog', () => {
|
||||||
@@ -112,7 +112,7 @@ describe('Publish Database Dialog', () => {
|
|||||||
|
|
||||||
should(profile).deepEqual(expectedGenScript);
|
should(profile).deepEqual(expectedGenScript);
|
||||||
|
|
||||||
const expectedContainerPublishProfile: IDeployProfile = {
|
const expectedContainerPublishProfile: ILocalDbDeployProfile = {
|
||||||
localDbSetting: {
|
localDbSetting: {
|
||||||
dbName: 'MockDatabaseName',
|
dbName: 'MockDatabaseName',
|
||||||
dockerBaseImage: '',
|
dockerBaseImage: '',
|
||||||
@@ -136,7 +136,7 @@ describe('Publish Database Dialog', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
dialog.object.publishToExistingServer = false;
|
dialog.object.publishToExistingServer = false;
|
||||||
let deployProfile: IDeployProfile | undefined;
|
let deployProfile: ILocalDbDeployProfile | undefined;
|
||||||
dialog.object.publishToContainer = (_, prof) => { deployProfile = prof; };
|
dialog.object.publishToContainer = (_, prof) => { deployProfile = prof; };
|
||||||
await dialog.object.publishClick();
|
await dialog.object.publishClick();
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
502
extensions/types/vscode-mssql.d.ts
vendored
502
extensions/types/vscode-mssql.d.ts
vendored
@@ -45,6 +45,11 @@ declare module 'vscode-mssql' {
|
|||||||
*/
|
*/
|
||||||
readonly azureAccountService: IAzureAccountService;
|
readonly azureAccountService: IAzureAccountService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for accessing Azure Resources functionality
|
||||||
|
*/
|
||||||
|
readonly azureResourceService: IAzureResourceService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompts the user to select an existing connection or create a new one, and then returns the result
|
* Prompts the user to select an existing connection or create a new one, and then returns the result
|
||||||
* @param ignoreFocusOut Whether the quickpick prompt ignores focus out (default false)
|
* @param ignoreFocusOut Whether the quickpick prompt ignores focus out (default false)
|
||||||
@@ -399,6 +404,13 @@ declare module 'vscode-mssql' {
|
|||||||
isSignedIn?: boolean;
|
isSignedIn?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IAzureAccountSession {
|
||||||
|
subscription: azure.subscription.Subscription,
|
||||||
|
tenantId: string,
|
||||||
|
account: IAccount,
|
||||||
|
token: Token
|
||||||
|
}
|
||||||
|
|
||||||
export interface TokenKey {
|
export interface TokenKey {
|
||||||
/**
|
/**
|
||||||
* Account Key - uniquely identifies an account
|
* Account Key - uniquely identifies an account
|
||||||
@@ -437,6 +449,38 @@ declare module 'vscode-mssql' {
|
|||||||
* Returns an access token for given user and tenant
|
* Returns an access token for given user and tenant
|
||||||
*/
|
*/
|
||||||
getAccountSecurityToken(account: IAccount, tenantId: string | undefined): Promise<Token>;
|
getAccountSecurityToken(account: IAccount, tenantId: string | undefined): Promise<Token>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Azure subscriptions with tenant and token for each given account
|
||||||
|
*/
|
||||||
|
getAccountSessions(account: IAccount): Promise<IAzureAccountSession[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAzureResourceService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Azure resource groups for given subscription
|
||||||
|
* @param session Azure session
|
||||||
|
* @returns List of resource groups
|
||||||
|
*/
|
||||||
|
getResourceGroups(session: IAzureAccountSession): Promise<azure.resources.ResourceGroup[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates or updates a Azure SQL server for given subscription, resource group and location
|
||||||
|
* @param session Azure session
|
||||||
|
* @param resourceGroupName resource group name
|
||||||
|
* @param serverName SQL server name
|
||||||
|
* @param parameters parameters for the SQL server
|
||||||
|
* @returns name of the SQL server
|
||||||
|
*/
|
||||||
|
createOrUpdateServer(session: IAzureAccountSession, resourceGroupName: string, serverName: string, parameters: azure.sql.Server): Promise<string | undefined>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Azure locations for given session
|
||||||
|
* @param session Azure session
|
||||||
|
* @returns List of locations
|
||||||
|
*/
|
||||||
|
getLocations(session: IAzureAccountSession): Promise<azure.subscription.Location[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum TaskExecutionMode {
|
export const enum TaskExecutionMode {
|
||||||
@@ -725,4 +769,462 @@ declare module 'vscode-mssql' {
|
|||||||
|
|
||||||
options: { [name: string]: any };
|
options: { [name: string]: any };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace for Azure APIs
|
||||||
|
*/
|
||||||
|
export namespace azure {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace for Azure Subscriptions. Types from @azure/arm-subscriptions module
|
||||||
|
*/
|
||||||
|
export namespace subscription {
|
||||||
|
/** Location information. */
|
||||||
|
interface Location {
|
||||||
|
/**
|
||||||
|
* The fully qualified ID of the location. For example, /subscriptions/00000000-0000-0000-0000-000000000000/locations/westus.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly id?: string;
|
||||||
|
/**
|
||||||
|
* The subscription ID.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly subscriptionId?: string;
|
||||||
|
/**
|
||||||
|
* The location name.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly name?: string;
|
||||||
|
/**
|
||||||
|
* The display name of the location.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly displayName?: string;
|
||||||
|
/**
|
||||||
|
* The latitude of the location.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly latitude?: string;
|
||||||
|
/**
|
||||||
|
* The longitude of the location.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly longitude?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Subscription information. */
|
||||||
|
export interface Subscription {
|
||||||
|
/**
|
||||||
|
* The fully qualified ID for the subscription. For example, /subscriptions/00000000-0000-0000-0000-000000000000.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly id?: string;
|
||||||
|
/**
|
||||||
|
* The subscription ID.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly subscriptionId?: string;
|
||||||
|
/**
|
||||||
|
* The subscription display name.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly displayName?: string;
|
||||||
|
/**
|
||||||
|
* The subscription state. Possible values are Enabled, Warned, PastDue, Disabled, and Deleted.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly state?: SubscriptionState;
|
||||||
|
/** The subscription policies. */
|
||||||
|
subscriptionPolicies?: SubscriptionPolicies;
|
||||||
|
/** The authorization source of the request. Valid values are one or more combinations of Legacy, RoleBased, Bypassed, Direct and Management. For example, 'Legacy, RoleBased'. */
|
||||||
|
authorizationSource?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Defines values for SubscriptionState. */
|
||||||
|
export type SubscriptionState = 'Enabled' | 'Warned' | 'PastDue' | 'Disabled' | 'Deleted';
|
||||||
|
|
||||||
|
|
||||||
|
/** Subscription policies. */
|
||||||
|
export interface SubscriptionPolicies {
|
||||||
|
/**
|
||||||
|
* The subscription location placement ID. The ID indicates which regions are visible for a subscription. For example, a subscription with a location placement Id of Public_2014-09-01 has access to Azure public regions.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly locationPlacementId?: string;
|
||||||
|
/**
|
||||||
|
* The subscription quota ID.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly quotaId?: string;
|
||||||
|
/**
|
||||||
|
* The subscription spending limit.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly spendingLimit?: SpendingLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Defines values for SpendingLimit. */
|
||||||
|
export type SpendingLimit = 'On' | 'Off' | 'CurrentPeriodOff';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace for Azure resources. Types from @azure/arm-resources module
|
||||||
|
*/
|
||||||
|
export namespace resources {
|
||||||
|
export interface ResourceGroup {
|
||||||
|
/**
|
||||||
|
* The ID of the resource group.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly id?: string;
|
||||||
|
/**
|
||||||
|
* The name of the resource group.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly name?: string;
|
||||||
|
/**
|
||||||
|
* The type of the resource group.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly type?: string;
|
||||||
|
/** The resource group properties. */
|
||||||
|
properties?: ResourceGroupProperties;
|
||||||
|
/** The location of the resource group. It cannot be changed after the resource group has been created. It must be one of the supported Azure locations. */
|
||||||
|
location: string;
|
||||||
|
/** The ID of the resource that manages this resource group. */
|
||||||
|
managedBy?: string;
|
||||||
|
/** The tags attached to the resource group. */
|
||||||
|
tags?: {
|
||||||
|
[propertyName: string]: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The resource group properties. */
|
||||||
|
export interface ResourceGroupProperties {
|
||||||
|
/**
|
||||||
|
* The provisioning state.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly provisioningState?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResourceGroup {
|
||||||
|
/**
|
||||||
|
* The ID of the resource group.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly id?: string;
|
||||||
|
/**
|
||||||
|
* The name of the resource group.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly name?: string;
|
||||||
|
/**
|
||||||
|
* The type of the resource group.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly type?: string;
|
||||||
|
/** The resource group properties. */
|
||||||
|
properties?: ResourceGroupProperties;
|
||||||
|
/** The location of the resource group. It cannot be changed after the resource group has been created. It must be one of the supported Azure locations. */
|
||||||
|
location: string;
|
||||||
|
/** The ID of the resource that manages this resource group. */
|
||||||
|
managedBy?: string;
|
||||||
|
/** The tags attached to the resource group. */
|
||||||
|
tags?: {
|
||||||
|
[propertyName: string]: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The resource group properties. */
|
||||||
|
export interface ResourceGroupProperties {
|
||||||
|
/**
|
||||||
|
* The provisioning state.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly provisioningState?: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace for Azure SQL APIs. Types from @azure/arm-sql module
|
||||||
|
*/
|
||||||
|
export namespace sql {
|
||||||
|
|
||||||
|
/** ARM resource. */
|
||||||
|
export interface Resource {
|
||||||
|
/**
|
||||||
|
* Resource ID.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly id?: string;
|
||||||
|
/**
|
||||||
|
* Resource name.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly name?: string;
|
||||||
|
/**
|
||||||
|
* Resource type.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly type?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Azure Active Directory identity configuration for a resource. */
|
||||||
|
export interface UserIdentity {
|
||||||
|
/**
|
||||||
|
* The Azure Active Directory principal id.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly principalId?: string;
|
||||||
|
/**
|
||||||
|
* The Azure Active Directory client id.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly clientId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines values for IdentityType. \
|
||||||
|
* {@link KnownIdentityType} can be used interchangeably with IdentityType,
|
||||||
|
* this enum contains the known values that the service supports.
|
||||||
|
* ### Known values supported by the service
|
||||||
|
* **None** \
|
||||||
|
* **SystemAssigned** \
|
||||||
|
* **UserAssigned** \
|
||||||
|
* **SystemAssigned,UserAssigned**
|
||||||
|
*/
|
||||||
|
export type IdentityType = string;
|
||||||
|
|
||||||
|
/** Azure Active Directory identity configuration for a resource. */
|
||||||
|
export interface ResourceIdentity {
|
||||||
|
/** The resource ids of the user assigned identities to use */
|
||||||
|
userAssignedIdentities?: {
|
||||||
|
[propertyName: string]: UserIdentity;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The Azure Active Directory principal id.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly principalId?: string;
|
||||||
|
/** The identity type. Set this to 'SystemAssigned' in order to automatically create and assign an Azure Active Directory principal for the resource. */
|
||||||
|
type?: IdentityType;
|
||||||
|
/**
|
||||||
|
* The Azure Active Directory tenant id.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly tenantId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ARM tracked top level resource. */
|
||||||
|
export type TrackedResource = Resource & {
|
||||||
|
/** Resource location. */
|
||||||
|
location: string;
|
||||||
|
/** Resource tags. */
|
||||||
|
tags?: {
|
||||||
|
[propertyName: string]: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** An Azure SQL Database server. */
|
||||||
|
export type Server = TrackedResource & {
|
||||||
|
/** The Azure Active Directory identity of the server. */
|
||||||
|
identity?: ResourceIdentity;
|
||||||
|
/**
|
||||||
|
* Kind of sql server. This is metadata used for the Azure portal experience.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly kind?: string;
|
||||||
|
/** Administrator username for the server. Once created it cannot be changed. */
|
||||||
|
administratorLogin?: string;
|
||||||
|
/** The administrator login password (required for server creation). */
|
||||||
|
administratorLoginPassword?: string;
|
||||||
|
/** The version of the server. */
|
||||||
|
version?: string;
|
||||||
|
/**
|
||||||
|
* The state of the server.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly state?: string;
|
||||||
|
/**
|
||||||
|
* The fully qualified domain name of the server.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly fullyQualifiedDomainName?: string;
|
||||||
|
/**
|
||||||
|
* List of private endpoint connections on a server
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly privateEndpointConnections?: ServerPrivateEndpointConnection[];
|
||||||
|
/** Minimal TLS version. Allowed values: '1.0', '1.1', '1.2' */
|
||||||
|
minimalTlsVersion?: string;
|
||||||
|
/** Whether or not public endpoint access is allowed for this server. Value is optional but if passed in, must be 'Enabled' or 'Disabled' */
|
||||||
|
publicNetworkAccess?: ServerNetworkAccessFlag;
|
||||||
|
/**
|
||||||
|
* Whether or not existing server has a workspace created and if it allows connection from workspace
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly workspaceFeature?: ServerWorkspaceFeature;
|
||||||
|
/** The resource id of a user assigned identity to be used by default. */
|
||||||
|
primaryUserAssignedIdentityId?: string;
|
||||||
|
/** The Client id used for cross tenant CMK scenario */
|
||||||
|
federatedClientId?: string;
|
||||||
|
/** A CMK URI of the key to use for encryption. */
|
||||||
|
keyId?: string;
|
||||||
|
/** The Azure Active Directory identity of the server. */
|
||||||
|
administrators?: ServerExternalAdministrator;
|
||||||
|
/** Whether or not to restrict outbound network access for this server. Value is optional but if passed in, must be 'Enabled' or 'Disabled' */
|
||||||
|
restrictOutboundNetworkAccess?: ServerNetworkAccessFlag;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A private endpoint connection under a server */
|
||||||
|
export interface ServerPrivateEndpointConnection {
|
||||||
|
/**
|
||||||
|
* Resource ID.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly id?: string;
|
||||||
|
/**
|
||||||
|
* Private endpoint connection properties
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly properties?: PrivateEndpointConnectionProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines values for ServerNetworkAccessFlag. \
|
||||||
|
* {@link KnownServerNetworkAccessFlag} can be used interchangeably with ServerNetworkAccessFlag,
|
||||||
|
* this enum contains the known values that the service supports.
|
||||||
|
* ### Known values supported by the service
|
||||||
|
* **Enabled** \
|
||||||
|
* **Disabled**
|
||||||
|
*/
|
||||||
|
export type ServerNetworkAccessFlag = string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines values for ServerWorkspaceFeature. \
|
||||||
|
* {@link KnownServerWorkspaceFeature} can be used interchangeably with ServerWorkspaceFeature,
|
||||||
|
* this enum contains the known values that the service supports.
|
||||||
|
* ### Known values supported by the service
|
||||||
|
* **Connected** \
|
||||||
|
* **Disconnected**
|
||||||
|
*/
|
||||||
|
export type ServerWorkspaceFeature = string;
|
||||||
|
|
||||||
|
/** Properties of a active directory administrator. */
|
||||||
|
export interface ServerExternalAdministrator {
|
||||||
|
/** Type of the sever administrator. */
|
||||||
|
administratorType?: AdministratorType;
|
||||||
|
/** Principal Type of the sever administrator. */
|
||||||
|
principalType?: PrincipalType;
|
||||||
|
/** Login name of the server administrator. */
|
||||||
|
login?: string;
|
||||||
|
/** SID (object ID) of the server administrator. */
|
||||||
|
sid?: string;
|
||||||
|
/** Tenant ID of the administrator. */
|
||||||
|
tenantId?: string;
|
||||||
|
/** Azure Active Directory only Authentication enabled. */
|
||||||
|
azureADOnlyAuthentication?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Properties of a private endpoint connection. */
|
||||||
|
export interface PrivateEndpointConnectionProperties {
|
||||||
|
/** Private endpoint which the connection belongs to. */
|
||||||
|
privateEndpoint?: PrivateEndpointProperty;
|
||||||
|
/** Connection state of the private endpoint connection. */
|
||||||
|
privateLinkServiceConnectionState?: PrivateLinkServiceConnectionStateProperty;
|
||||||
|
/**
|
||||||
|
* State of the private endpoint connection.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly provisioningState?: PrivateEndpointProvisioningState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines values for AdministratorType. \
|
||||||
|
* {@link KnownAdministratorType} can be used interchangeably with AdministratorType,
|
||||||
|
* this enum contains the known values that the service supports.
|
||||||
|
* ### Known values supported by the service
|
||||||
|
* **ActiveDirectory**
|
||||||
|
*/
|
||||||
|
export type AdministratorType = string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines values for PrincipalType. \
|
||||||
|
* {@link KnownPrincipalType} can be used interchangeably with PrincipalType,
|
||||||
|
* this enum contains the known values that the service supports.
|
||||||
|
* ### Known values supported by the service
|
||||||
|
* **User** \
|
||||||
|
* **Group** \
|
||||||
|
* **Application**
|
||||||
|
*/
|
||||||
|
export type PrincipalType = string;
|
||||||
|
|
||||||
|
export interface PrivateEndpointProperty {
|
||||||
|
/** Resource id of the private endpoint. */
|
||||||
|
id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PrivateLinkServiceConnectionStateProperty {
|
||||||
|
/** The private link service connection status. */
|
||||||
|
status: PrivateLinkServiceConnectionStateStatus;
|
||||||
|
/** The private link service connection description. */
|
||||||
|
description: string;
|
||||||
|
/**
|
||||||
|
* The actions required for private link service connection.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
readonly actionsRequired?: PrivateLinkServiceConnectionStateActionsRequire;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines values for PrivateEndpointProvisioningState. \
|
||||||
|
* {@link KnownPrivateEndpointProvisioningState} can be used interchangeably with PrivateEndpointProvisioningState,
|
||||||
|
* this enum contains the known values that the service supports.
|
||||||
|
* ### Known values supported by the service
|
||||||
|
* **Approving** \
|
||||||
|
* **Ready** \
|
||||||
|
* **Dropping** \
|
||||||
|
* **Failed** \
|
||||||
|
* **Rejecting**
|
||||||
|
*/
|
||||||
|
export type PrivateEndpointProvisioningState = string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines values for PrivateLinkServiceConnectionStateStatus. \
|
||||||
|
* {@link KnownPrivateLinkServiceConnectionStateStatus} can be used interchangeably with PrivateLinkServiceConnectionStateStatus,
|
||||||
|
* this enum contains the known values that the service supports.
|
||||||
|
* ### Known values supported by the service
|
||||||
|
* **Approved** \
|
||||||
|
* **Pending** \
|
||||||
|
* **Rejected** \
|
||||||
|
* **Disconnected**
|
||||||
|
*/
|
||||||
|
export type PrivateLinkServiceConnectionStateStatus = string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines values for PrivateLinkServiceConnectionStateActionsRequire. \
|
||||||
|
* {@link KnownPrivateLinkServiceConnectionStateActionsRequire} can be used interchangeably with PrivateLinkServiceConnectionStateActionsRequire,
|
||||||
|
* this enum contains the known values that the service supports.
|
||||||
|
* ### Known values supported by the service
|
||||||
|
* **None**
|
||||||
|
*/
|
||||||
|
export type PrivateLinkServiceConnectionStateActionsRequire = string;
|
||||||
|
|
||||||
|
export interface PrivateLinkServiceConnectionStateProperty {
|
||||||
|
/** The private link service connection status. */
|
||||||
|
status: PrivateLinkServiceConnectionStateStatus;
|
||||||
|
/** The private link service connection description. */
|
||||||
|
description: string;
|
||||||
|
/**
|
||||||
|
* The actions required for private link service connection.
|
||||||
|
* NOTE: This property will not be serialized. It can only be populated by the server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
readonly actionsRequired?: PrivateLinkServiceConnectionStateActionsRequire;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user