mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
SQL Proj - Added an option to deploy to docker to select the base image (#17067)
* Added an option to deploy to docker to select the base image
This commit is contained in:
@@ -135,12 +135,13 @@ export const enterPortNumber = localize('enterPortNumber', "Enter port number or
|
|||||||
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 const enterPassword = localize('enterPassword', "Enter password");
|
export const enterPassword = localize('enterPassword', "Enter password");
|
||||||
|
export const enterBaseImage = localize('enterBaseImage', "Enter the base SQL Server docker image or press enter to use the default value");
|
||||||
export const portMustBeNumber = localize('portMustNotBeNumber', "Port must a be number");
|
export const portMustBeNumber = localize('portMustNotBeNumber', "Port must a be number");
|
||||||
export const valueCannotBeEmpty = localize('valueCannotBeEmpty', "Value cannot be empty");
|
export const valueCannotBeEmpty = localize('valueCannotBeEmpty', "Value cannot be empty");
|
||||||
export const dockerImageLabelPrefix = 'source=sqldbproject';
|
export const dockerImageLabelPrefix = 'source=sqldbproject';
|
||||||
export const dockerImageNamePrefix = 'sqldbproject';
|
export const dockerImageNamePrefix = 'sqldbproject';
|
||||||
export const connectionNamePrefix = 'SQLDbProject';
|
export const connectionNamePrefix = 'SQLDbProject';
|
||||||
export const dockerBaseImage = 'mcr.microsoft.com/azure-sql-edge:latest';
|
export const defaultDockerBaseImage = 'mcr.microsoft.com/mssql/server:2019-latest';
|
||||||
export const commandsFolderName = 'commands';
|
export const commandsFolderName = 'commands';
|
||||||
export const mssqlFolderName = '.mssql';
|
export const mssqlFolderName = '.mssql';
|
||||||
export const dockerFileName = 'Dockerfile';
|
export const dockerFileName = 'Dockerfile';
|
||||||
|
|||||||
@@ -104,12 +104,27 @@ export async function launchPublishToDockerContainerQuickpick(project: Project):
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let baseImage: string | undefined = '';
|
||||||
|
baseImage = await vscode.window.showInputBox({
|
||||||
|
title: constants.enterBaseImage,
|
||||||
|
ignoreFocusOut: true,
|
||||||
|
value: constants.defaultDockerBaseImage,
|
||||||
|
validateInput: input => utils.isEmptyString(input) ? constants.valueCannotBeEmpty : undefined
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return when user hits escape
|
||||||
|
if (!baseImage) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
localDbSetting = {
|
localDbSetting = {
|
||||||
serverName: 'localhost',
|
serverName: 'localhost',
|
||||||
userName: 'sa',
|
userName: 'sa',
|
||||||
dbName: project.projectFileName,
|
dbName: project.projectFileName,
|
||||||
password: password,
|
password: password,
|
||||||
port: +portNumber,
|
port: +portNumber,
|
||||||
|
dockerBaseImage: baseImage
|
||||||
};
|
};
|
||||||
|
|
||||||
let deploySettings = await getPublishDatabaseSettings(project, false);
|
let deploySettings = await getPublishDatabaseSettings(project, false);
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IDeploySettings } from '../IDeploySettings';
|
import { IDeploySettings } from '../IDeploySettings';
|
||||||
|
|
||||||
export enum AppSettingType {
|
export enum AppSettingType {
|
||||||
@@ -21,4 +26,6 @@ export interface ILocalDbSetting {
|
|||||||
userName: string,
|
userName: string,
|
||||||
password: string,
|
password: string,
|
||||||
dbName: string,
|
dbName: string,
|
||||||
|
dockerBaseImage: string,
|
||||||
|
connectionRetryTimeout?: number
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ export class DeployService {
|
|||||||
constructor(private _outputChannel: vscode.OutputChannel) {
|
constructor(private _outputChannel: vscode.OutputChannel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DefaultSqlRetryTimeoutInSec: number = 10;
|
||||||
|
private DefaultSqlNumberOfRetries: number = 10;
|
||||||
|
|
||||||
private createConnectionStringTemplate(runtime: string | undefined): string {
|
private createConnectionStringTemplate(runtime: string | undefined): string {
|
||||||
switch (runtime?.toLocaleLowerCase()) {
|
switch (runtime?.toLocaleLowerCase()) {
|
||||||
case 'dotnet':
|
case 'dotnet':
|
||||||
@@ -106,7 +109,7 @@ export class DeployService {
|
|||||||
// Create commands
|
// Create commands
|
||||||
//
|
//
|
||||||
|
|
||||||
await this.createCommands(mssqlFolderPath, commandsFolderPath, dockerFilePath, startFilePath, imageLabel);
|
await this.createCommands(mssqlFolderPath, commandsFolderPath, dockerFilePath, startFilePath, imageLabel, profile.localDbSetting.dockerBaseImage);
|
||||||
|
|
||||||
this.logToOutput(constants.runningDockerMessage);
|
this.logToOutput(constants.runningDockerMessage);
|
||||||
// Building the image and running the docker
|
// Building the image and running the docker
|
||||||
@@ -144,7 +147,7 @@ export class DeployService {
|
|||||||
|
|
||||||
private async buildAndRunDockerContainer(dockerFilePath: string, imageName: string, root: string, profile: ILocalDbSetting, imageLabel: string): Promise<string | undefined> {
|
private async buildAndRunDockerContainer(dockerFilePath: string, imageName: string, root: string, profile: ILocalDbSetting, imageLabel: string): Promise<string | undefined> {
|
||||||
this.logToOutput('Building docker image ...');
|
this.logToOutput('Building docker image ...');
|
||||||
await utils.executeCommand(`docker pull ${constants.dockerBaseImage}`, this._outputChannel);
|
await utils.executeCommand(`docker pull ${profile.dockerBaseImage}`, this._outputChannel);
|
||||||
await utils.executeCommand(`docker build -f ${dockerFilePath} -t ${imageName} ${root}`, this._outputChannel);
|
await utils.executeCommand(`docker build -f ${dockerFilePath} -t ${imageName} ${root}`, this._outputChannel);
|
||||||
await utils.executeCommand(`docker images --filter label=${imageLabel}`, this._outputChannel);
|
await utils.executeCommand(`docker images --filter label=${imageLabel}`, this._outputChannel);
|
||||||
|
|
||||||
@@ -254,7 +257,7 @@ export class DeployService {
|
|||||||
return connectionResult ? connectionResult.connectionId : <string>connection;
|
return connectionResult ? connectionResult.connectionId : <string>connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getConnection(profile: ILocalDbSetting, savePassword: boolean, database: string, timeoutInSeconds: number = 5): Promise<string | undefined> {
|
public async getConnection(profile: ILocalDbSetting, savePassword: 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.connectingToSqlServerOnDockerMessage,
|
constants.connectingToSqlServerOnDockerMessage,
|
||||||
@@ -264,7 +267,7 @@ export class DeployService {
|
|||||||
this.validateConnection,
|
this.validateConnection,
|
||||||
this.formatConnectionResult,
|
this.formatConnectionResult,
|
||||||
this._outputChannel,
|
this._outputChannel,
|
||||||
5, timeoutInSeconds);
|
this.DefaultSqlNumberOfRetries, profile.connectionRetryTimeout || this.DefaultSqlRetryTimeoutInSec);
|
||||||
|
|
||||||
if (connection) {
|
if (connection) {
|
||||||
const connectionResult = <ConnectionResult>connection;
|
const connectionResult = <ConnectionResult>connection;
|
||||||
@@ -311,7 +314,7 @@ export class DeployService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates command file and docker file needed for deploy operation
|
// Creates command file and docker file needed for deploy operation
|
||||||
private async createCommands(mssqlFolderPath: string, commandsFolderPath: string, dockerFilePath: string, startFilePath: string, imageLabel: string): Promise<void> {
|
private async createCommands(mssqlFolderPath: string, commandsFolderPath: string, dockerFilePath: string, startFilePath: string, imageLabel: string, baseImage: string): Promise<void> {
|
||||||
// Create mssql folders if doesn't exist
|
// Create mssql folders if doesn't exist
|
||||||
//
|
//
|
||||||
await utils.createFolderIfNotExist(mssqlFolderPath);
|
await utils.createFolderIfNotExist(mssqlFolderPath);
|
||||||
@@ -328,7 +331,7 @@ export class DeployService {
|
|||||||
//
|
//
|
||||||
await this.createFile(dockerFilePath,
|
await this.createFile(dockerFilePath,
|
||||||
`
|
`
|
||||||
FROM ${constants.dockerBaseImage}
|
FROM ${baseImage}
|
||||||
ENV ACCEPT_EULA=Y
|
ENV ACCEPT_EULA=Y
|
||||||
ENV MSSQL_PID=Developer
|
ENV MSSQL_PID=Developer
|
||||||
LABEL ${imageLabel}
|
LABEL ${imageLabel}
|
||||||
|
|||||||
@@ -71,7 +71,9 @@ describe('deploy service', function (): void {
|
|||||||
password: 'PLACEHOLDER',
|
password: 'PLACEHOLDER',
|
||||||
port: 1433,
|
port: 1433,
|
||||||
serverName: 'localhost',
|
serverName: 'localhost',
|
||||||
userName: 'sa'
|
userName: 'sa',
|
||||||
|
dockerBaseImage: 'image',
|
||||||
|
connectionRetryTimeout: 1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
const projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
||||||
@@ -93,7 +95,9 @@ describe('deploy service', function (): void {
|
|||||||
password: 'PLACEHOLDER',
|
password: 'PLACEHOLDER',
|
||||||
port: 1433,
|
port: 1433,
|
||||||
serverName: 'localhost',
|
serverName: 'localhost',
|
||||||
userName: 'sa'
|
userName: 'sa',
|
||||||
|
dockerBaseImage: 'image',
|
||||||
|
connectionRetryTimeout: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
const deployService = new DeployService(testContext.outputChannel);
|
const deployService = new DeployService(testContext.outputChannel);
|
||||||
@@ -103,7 +107,7 @@ describe('deploy service', function (): void {
|
|||||||
sandbox.stub(azdata.connection, 'getUriForConnection').returns(Promise.resolve('connection'));
|
sandbox.stub(azdata.connection, 'getUriForConnection').returns(Promise.resolve('connection'));
|
||||||
sandbox.stub(azdata.tasks, 'startBackgroundOperation').callThrough();
|
sandbox.stub(azdata.tasks, 'startBackgroundOperation').callThrough();
|
||||||
sandbox.stub(childProcess, 'exec').yields(undefined, 'id');
|
sandbox.stub(childProcess, 'exec').yields(undefined, 'id');
|
||||||
let connection = await deployService.getConnection(localDbSettings, false, 'master', 2);
|
let connection = await deployService.getConnection(localDbSettings, false, 'master');
|
||||||
should(connection).equals('connection');
|
should(connection).equals('connection');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -138,7 +142,8 @@ describe('deploy service', function (): void {
|
|||||||
password: 'PLACEHOLDER',
|
password: 'PLACEHOLDER',
|
||||||
port: 1433,
|
port: 1433,
|
||||||
serverName: 'localhost',
|
serverName: 'localhost',
|
||||||
userName: 'sa'
|
userName: 'sa',
|
||||||
|
dockerBaseImage: 'image'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user