sqlproj publish to container - october release improvements (#17289)

This commit is contained in:
Leila Lali
2021-10-07 12:55:43 -07:00
committed by GitHub
parent 04ee2c5d83
commit f875699cd2
5 changed files with 67 additions and 29 deletions

View File

@@ -160,7 +160,8 @@ export const enterConnStringTemplateDescription = localize('enterConnStringTempl
export const appSettingPrompt = localize('appSettingPrompt', "Would you like to update Azure Function local.settings.json with the new connection string?");
export const enterConnectionStringEnvNameDescription = localize('enterConnectionStringEnvNameDescription', "Enter environment variable for SQL connection string");
export const deployDbTaskName = localize('deployDbTaskName', "Deploying SQL Db Project Locally");
export const deployProjectSucceed = localize('deployProjectSucceed', "Database project deployed successfully");
export const publishProjectSucceed = localize('publishProjectSucceed', "Database project published successfully");
export const publishingProjectMessage = localize('publishingProjectMessage', "Publishing project in a container...");
export const cleaningDockerImagesMessage = localize('cleaningDockerImagesMessage', "Cleaning existing deployments...");
export const creatingDeploymentSettingsMessage = localize('creatingDeploymentSettingsMessage', "Creating deployment settings ...");
export const runningDockerMessage = localize('runningDockerMessage', "Building and running the docker container ...");
@@ -169,8 +170,10 @@ export const dockerContainerNotRunningErrorMessage = localize('dockerContainerNo
export const dockerContainerFailedToRunErrorMessage = localize('dockerContainerFailedToRunErrorMessage', "Failed to run the docker container");
export const connectingToSqlServerOnDockerMessage = localize('connectingToSqlServerOnDockerMessage', "Connecting to SQL Server on Docker");
export const deployProjectFailedMessage = localize('deployProjectFailedMessage', "Failed to open a connection to the deployed database'");
export const containerAlreadyExistForProject = localize('containerAlreadyExistForProject', "Other servers on container already exist for the project. Do you want to delete them?'");
export const checkoutOutputMessage = localize('checkoutOutputMessage', "Check output pane for more details.");
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. Check output pane for more details. {0}", errorMessage); }
export function publishToContainerFailed(errorMessage: string) { return localize('publishToContainerFailed', "Failed to publish to container. {0}", errorMessage); }
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 connectionFailedError(error: string) { return localize('connectionFailedError', "Connection failed error: '{0}'", error); }

View File

@@ -437,6 +437,12 @@ export async function executeCommand(cmd: string, outputChannel: vscode.OutputCh
timeout: timeout
}, (err, stdout) => {
if (err) {
// removing sensitive data from the exception
sensitiveData.forEach(element => {
err.cmd = err.cmd?.replace(element, '***');
err.message = err.message?.replace(element, '***');
});
reject(err);
} else {
resolve(stdout);
@@ -552,3 +558,18 @@ export function isValidSQLPassword(password: string, userName: string = 'sa'): b
const hasNonAlphas = /\W/.test(password) ? 1 : 0;
return !containsUserName && password.length >= 8 && password.length <= 128 && (hasUpperCase + hasLowerCase + hasNumbers + hasNonAlphas >= 3);
}
export async function showErrorMessageWithOutputChannel(errorMessageFunc: (error: string) => string, error: any, outputChannel: vscode.OutputChannel): Promise<void> {
const result = await vscode.window.showErrorMessage(errorMessageFunc(getErrorMessage(error)), constants.checkoutOutputMessage);
if (result !== undefined) {
outputChannel.show();
}
}
export async function showInfoMessageWithOutputChannel(message: string, outputChannel: vscode.OutputChannel): Promise<void> {
const result = await vscode.window.showInformationMessage(message, constants.checkoutOutputMessage);
if (result !== undefined) {
outputChannel.show();
}
}

View File

@@ -73,11 +73,11 @@ export class ProjectsController {
projFileWatchers = new Map<string, vscode.FileSystemWatcher>();
constructor(outputChannel: vscode.OutputChannel) {
this.netCoreTool = new NetCoreTool(outputChannel);
constructor(private _outputChannel: vscode.OutputChannel) {
this.netCoreTool = new NetCoreTool(this._outputChannel);
this.buildHelper = new BuildHelper();
this.deployService = new DeployService(outputChannel);
this.autorestHelper = new AutorestHelper(outputChannel);
this.deployService = new DeployService(this._outputChannel);
this.autorestHelper = new AutorestHelper(this._outputChannel);
}
public getDashboardPublishData(projectFile: string): (string | dataworkspace.IconCellValue)[][] {
@@ -270,6 +270,7 @@ export class ProjectsController {
if (deployProfile && deployProfile.deploySettings) {
let connectionUri: string | undefined;
if (deployProfile.localDbSetting) {
void utils.showInfoMessageWithOutputChannel(constants.publishingProjectMessage, this._outputChannel);
connectionUri = await this.deployService.deploy(deployProfile, project);
if (connectionUri) {
deployProfile.deploySettings.connectionUri = connectionUri;
@@ -281,16 +282,16 @@ export class ProjectsController {
if (deployProfile.localDbSetting) {
await this.deployService.getConnection(deployProfile.localDbSetting, true, deployProfile.localDbSetting.dbName);
}
void vscode.window.showInformationMessage(constants.deployProjectSucceed);
void vscode.window.showInformationMessage(constants.publishProjectSucceed);
} else {
void vscode.window.showErrorMessage(constants.publishToContainerFailed(publishResult?.errorMessage || ''));
void utils.showErrorMessageWithOutputChannel(constants.publishToContainerFailed, publishResult?.errorMessage || '', this._outputChannel);
}
} else {
void vscode.window.showErrorMessage(constants.publishToContainerFailed(constants.deployProjectFailedMessage));
void utils.showErrorMessageWithOutputChannel(constants.publishToContainerFailed, constants.deployProjectFailedMessage, this._outputChannel);
}
}
} catch (error) {
void vscode.window.showErrorMessage(constants.publishToContainerFailed(utils.getErrorMessage(error)));
void utils.showErrorMessageWithOutputChannel(constants.publishToContainerFailed, error, this._outputChannel);
}
return;
}

View File

@@ -111,11 +111,15 @@ export class DeployService {
const dockerFilePath = path.join(mssqlFolderPath, constants.dockerFileName);
const startFilePath = path.join(commandsFolderPath, constants.startCommandName);
this.logToOutput(constants.cleaningDockerImagesMessage);
// Clean up existing docker image
await this.cleanDockerObjects(`docker ps -q -a --filter label=${imageLabel}`, ['docker stop', 'docker rm']);
await this.cleanDockerObjects(`docker images -f label=${imageLabel} -q`, [`docker rmi -f `]);
const containerIds = await this.getCurrentDockerContainer(imageLabel);
if (containerIds && containerIds.length > 0) {
const result = await vscode.window.showWarningMessage(constants.containerAlreadyExistForProject, constants.yesString, constants.noString);
if (result === constants.yesString) {
this.logToOutput(constants.cleaningDockerImagesMessage);
await this.cleanDockerObjects(containerIds, ['docker stop', 'docker rm']);
}
}
this.logToOutput(constants.creatingDeploymentSettingsMessage);
// Create commands
@@ -363,17 +367,22 @@ RUN ["/bin/bash", "/opt/commands/start.sh"]
await fse.writeFile(filePath, content);
}
public async cleanDockerObjects(commandToGetObjects: string, commandsToClean: string[]): Promise<void> {
const currentIds = await utils.executeCommand(commandToGetObjects, this._outputChannel);
if (currentIds) {
const ids = currentIds.split(/\r?\n/);
for (let index = 0; index < ids.length; index++) {
const id = ids[index];
if (id) {
for (let commandId = 0; commandId < commandsToClean.length; commandId++) {
const command = commandsToClean[commandId];
await utils.executeCommand(`${command} ${id}`, this._outputChannel);
}
private async getCurrentIds(commandToRun: string): Promise<string[]> {
const currentIds = await utils.executeCommand(commandToRun, this._outputChannel);
return currentIds ? currentIds.split(/\r?\n/) : [];
}
public async getCurrentDockerContainer(imageLabel: string): Promise<string[]> {
return await this.getCurrentIds(`docker ps -q -a --filter label=${imageLabel}`);
}
public async cleanDockerObjects(ids: string[], commandsToClean: string[]): Promise<void> {
for (let index = 0; index < ids.length; index++) {
const id = ids[index];
if (id) {
for (let commandId = 0; commandId < commandsToClean.length; commandId++) {
const command = commandsToClean[commandId];
await utils.executeCommand(`${command} ${id}`, this._outputChannel);
}
}
}

View File

@@ -15,6 +15,7 @@ import * as childProcess from 'child_process';
import { AppSettingType, IDeployProfile } from '../../models/deploy/deployProfile';
let fse = require('fs-extra');
let path = require('path');
import * as constants from '../../common/constants';
export interface TestContext {
outputChannel: vscode.OutputChannel;
@@ -81,6 +82,7 @@ describe('deploy service', function (): void {
const deployService = new DeployService(testContext.outputChannel);
sandbox.stub(azdata.connection, 'connect').returns(Promise.resolve(mockConnectionResult));
sandbox.stub(azdata.connection, 'getUriForConnection').returns(Promise.resolve('connection'));
sandbox.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve(constants.yesString));
sandbox.stub(azdata.tasks, 'startBackgroundOperation').callThrough();
sandbox.stub(childProcess, 'exec').yields(undefined, 'id');
let connection = await deployService.deploy(deployProfile, project1);
@@ -168,10 +170,12 @@ describe('deploy service', function (): void {
}
};
const appInteg = {appSettingType: AppSettingType.AzureFunction,
const appInteg = {
appSettingType: AppSettingType.AzureFunction,
appSettingFile: filePath,
deploySettings: undefined,
envVariableName: 'SQLConnectionString'};
envVariableName: 'SQLConnectionString'
};
const deployService = new DeployService(testContext.outputChannel);
sandbox.stub(childProcess, 'exec').yields(undefined, 'id');
@@ -240,8 +244,8 @@ describe('deploy service', function (): void {
id2
id3`);
await deployService.cleanDockerObjects(`docker ps -q -a --filter label=test`, ['docker stop', 'docker rm']);
const ids = await deployService.getCurrentDockerContainer('label');
await deployService.cleanDockerObjects(ids, ['docker stop', 'docker rm']);
should(process.calledThrice);
});
});