SQL Project Deploy to docker container - Adding a UI for user to select docker image tag (#19297)

This commit is contained in:
Leila Lali
2022-05-11 11:29:11 -07:00
committed by GitHub
parent 65ef41d53d
commit e10b1eb5a9
10 changed files with 301 additions and 30 deletions

View File

@@ -275,7 +275,8 @@ export async function launchCreateAzureServerQuickPick(project: Project, azureSq
* 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<ILocalDbDeployProfile | undefined> {
const name = uiUtils.getPublishServerName(project.getProjectTargetVersion());
const target = project.getProjectTargetVersion();
const name = uiUtils.getPublishServerName(target);
let localDbSetting: ILocalDbSetting | undefined;
// Deploy to docker selected
let portNumber = await vscode.window.showInputBox({
@@ -321,10 +322,10 @@ export async function launchPublishToDockerContainerQuickpick(project: Project):
return undefined;
}
const baseImages = uiUtils.getDockerBaseImages(project.getProjectTargetVersion());
const baseImages = uiUtils.getDockerBaseImages(target);
const baseImage = await vscode.window.showQuickPick(
baseImages.map(x => x.displayName),
{ title: constants.selectBaseImage(name), ignoreFocusOut: true });
{ title: constants.selectBaseImage(name), ignoreFocusOut: true, placeHolder: uiUtils.getDockerImagePlaceHolder(target) });
// Return when user hits escape
if (!baseImage) {
@@ -332,19 +333,50 @@ export async function launchPublishToDockerContainerQuickpick(project: Project):
}
const imageInfo = baseImages.find(x => x.displayName === baseImage);
if (!imageInfo) {
return undefined;
}
const eulaAccepted = await launchEulaQuickPick(imageInfo);
if (!eulaAccepted) {
return undefined;
}
let imageTags = await uiUtils.getImageTags(imageInfo, target);
let imageTagsItems: vscode.QuickPickItem[] = imageTags.map(tag => { return { label: tag }; });
if (imageInfo.defaultTag) {
// move the default to be the first one in the list
const defaultIndex = imageTagsItems.findIndex(i => i.label === imageInfo.defaultTag);
if (defaultIndex > -1) {
imageTagsItems.splice(defaultIndex, 1);
}
// add default next to the default value
imageTagsItems.unshift({ label: imageInfo.defaultTag, description: constants.defaultQuickPickItem });
}
const imageTag = await vscode.window.showQuickPick(
imageTagsItems,
{ title: constants.selectImageTag(name), ignoreFocusOut: true });
if (!imageTag) {
return undefined;
}
// Add the image tag if it's not the latest
let imageName = imageInfo.name;
if (imageTag && imageTag.label !== constants.dockerImageDefaultTag) {
imageName = `${imageName}:${imageTag.label}`;
}
localDbSetting = {
serverName: constants.defaultLocalServerName,
userName: constants.defaultLocalServerAdminName,
dbName: project.projectFileName,
password: password,
port: +portNumber,
dockerBaseImage: imageInfo?.name || '',
dockerBaseImageEula: imageInfo?.agreementInfo?.link?.url || ''
dockerBaseImage: imageName,
dockerBaseImageEula: imageInfo.agreementInfo.link.url
};
let deploySettings = await getPublishDatabaseSettings(project, false);
@@ -360,7 +392,6 @@ export async function launchPublishToDockerContainerQuickpick(project: Project):
// Get the database name from deploy settings
localDbSetting.dbName = deploySettings.databaseName;
return {
localDbSetting: localDbSetting,
deploySettings: deploySettings,

View File

@@ -213,9 +213,13 @@ export async function launchPublishTargetOption(project: Project): Promise<const
const target = project.getProjectTargetVersion();
const name = getPublishServerName(target);
const logicalServerName = target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure) ? constants.AzureSqlLogicalServerName : constants.SqlServerName;
// Options list based on target
const options = target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure) ?
[constants.publishToDockerContainer(name), constants.publishToNewAzureServer, constants.publishToExistingServer(logicalServerName)] :
[constants.publishToAzureEmulator, constants.publishToNewAzureServer, constants.publishToExistingServer(logicalServerName)] :
[constants.publishToDockerContainer(name), constants.publishToExistingServer(logicalServerName)];
// Show the options to the user
const publishOption = await vscode.window.showQuickPick(
options,
{ title: constants.selectPublishOption, ignoreFocusOut: true });
@@ -225,11 +229,14 @@ export async function launchPublishTargetOption(project: Project): Promise<const
return undefined;
}
// Map the title to the publish option type
switch (publishOption) {
case constants.publishToExistingServer(name):
return constants.PublishTargetType.existingServer;
case constants.publishToDockerContainer(name):
return constants.PublishTargetType.docker;
case constants.publishToAzureEmulator:
return constants.PublishTargetType.docker;
case constants.publishToNewAzureServer:
return constants.PublishTargetType.newAzureServer;
default:

View File

@@ -5,6 +5,8 @@
import { SqlTargetPlatform } from 'sqldbproj';
import * as constants from '../common/constants';
import * as utils from '../common/utils';
import { HttpClient } from '../common/httpClient';
import { AgreementInfo, DockerImageInfo } from '../models/deploy/deployProfile';
/**
@@ -38,58 +40,117 @@ export function getPublishServerName(target: string): string {
return target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure) ? constants.AzureSqlServerName : constants.SqlServerName;
}
/**
* Returns the docker image place holder based on the target version
*/
export function getDockerImagePlaceHolder(target: string): string {
return target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure) ?
constants.dockerImagesPlaceHolder(constants.AzureSqlDbLiteDockerImageName) :
constants.dockerImagesPlaceHolder(SqlTargetPlatform.sqlEdge);
}
/**
* Returns the list of image tags for given target
* @param imageInfo docker image info
* @param target project target version
* @returns image tags
*/
export async function getImageTags(imageInfo: DockerImageInfo, target: string): Promise<string[]> {
let imageTags: string[] | undefined = [];
const versionToImageTags: Map<number, string[]> = new Map<number, string[]>();
try {
const imageTagsFromUrl = await HttpClient.getRequest(imageInfo?.tagsUrl, true);
if (imageTagsFromUrl?.tags) {
// Create a map for version and tags and find the max version in the list
let defaultVersion: number = 0;
let maxVersionNumber: number = defaultVersion;
(imageTagsFromUrl.tags as string[]).forEach(imageTag => {
const version = utils.findSqlVersionInImageName(imageTag) || defaultVersion;
let tags = versionToImageTags.has(version) ? versionToImageTags.get(version) : [];
tags = tags ?? [];
tags = tags?.concat(imageTag);
versionToImageTags.set(version, tags);
maxVersionNumber = version && version > maxVersionNumber ? version : maxVersionNumber;
});
// Find the version maps to the target framework and default to max version in the tags
const targetVersion = utils.findSqlVersionInTargetPlatform(constants.getTargetPlatformFromVersion(target)) || maxVersionNumber;
// Get the image tags with no version of the one that matches project platform
versionToImageTags.forEach((tags: string[], version: number) => {
if (version === defaultVersion || version >= targetVersion) {
imageTags = imageTags?.concat(tags);
}
});
imageTags = imageTags ?? [];
imageTags = imageTags.sort((a, b) => a.indexOf(constants.dockerImageDefaultTag) > 0 ? -1 : a.localeCompare(b));
}
} catch (err) {
// Ignore the error. If http request fails, we just use the default tag
console.debug(`Failed to get docker image tags ${err}`);
}
return imageTags;
}
/**
* Returns the list of base images for given target version
* @param target
* @returns list of image info
*/
export function getDockerBaseImages(target: string): DockerImageInfo[] {
if (target === constants.targetPlatformToVersion.get(SqlTargetPlatform.sqlAzure)) {
return [{
name: `${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}:2019-latest`,
displayName: SqlTargetPlatform.sqlServer2019,
name: `${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}`,
displayName: constants.AzureSqlDbFullDockerImageName,
agreementInfo: {
link: {
text: constants.eulaAgreementTitle,
url: constants.sqlServerEulaLink,
}
}
},
tagsUrl: `https://${constants.sqlServerDockerRegistry}/v2/${constants.sqlServerDockerRepository}/tags/list`,
defaultTag: constants.dockerImageDefaultTag
}, {
name: `${constants.sqlServerDockerRegistry}/${constants.azureSqlEdgeDockerRepository}:latest`,
displayName: SqlTargetPlatform.sqlEdge,
name: `${constants.sqlServerDockerRegistry}/${constants.azureSqlEdgeDockerRepository}`,
displayName: constants.AzureSqlDbLiteDockerImageName,
agreementInfo: {
link: {
text: constants.edgeEulaAgreementTitle,
url: constants.sqlServerEdgeEulaLink,
}
}
},
tagsUrl: `https://${constants.sqlServerDockerRegistry}/v2/${constants.azureSqlEdgeDockerRepository}/tags/list`,
defaultTag: constants.dockerImageDefaultTag
}];
} else {
return [
{
name: `${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}:2017-latest`,
displayName: SqlTargetPlatform.sqlServer2017,
name: `${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}`,
displayName: constants.SqlServerDockerImageName,
agreementInfo: {
link: {
text: constants.eulaAgreementTitle,
url: constants.sqlServerEulaLink,
}
}
},
tagsUrl: `https://${constants.sqlServerDockerRegistry}/v2/${constants.sqlServerDockerRepository}/tags/list`,
defaultTag: constants.dockerImageDefaultTag
},
{
name: `${constants.sqlServerDockerRegistry}/${constants.sqlServerDockerRepository}:2019-latest`,
displayName: SqlTargetPlatform.sqlServer2019,
agreementInfo: {
link: {
text: constants.eulaAgreementTitle,
url: constants.sqlServerEulaLink,
}
}
},
{
name: `${constants.sqlServerDockerRegistry}/${constants.azureSqlEdgeDockerRepository}:latest`,
name: `${constants.sqlServerDockerRegistry}/${constants.azureSqlEdgeDockerRepository}`,
displayName: SqlTargetPlatform.sqlEdge,
agreementInfo: {
link: {
text: constants.edgeEulaAgreementTitle,
url: constants.sqlServerEdgeEulaLink,
}
}
},
tagsUrl: `https://${constants.sqlServerDockerRegistry}/v2/${constants.azureSqlEdgeDockerRepository}/tags/list`,
defaultTag: constants.dockerImageDefaultTag
},
];
}