in extensions/azurePublish/src/node/azureResourceManager/azureResourceManager.ts [255:476]
public async deployQnAReource(config: QnAResourceConfig): Promise<{ endpoint: string; subscriptionKey: string }> {
try {
this.logger({
status: BotProjectDeployLoggerType.PROVISION_INFO,
message: 'Deploying QnA Resource ...',
});
// initialize the name
const qnaMakerServiceName = `${config.name}-qna`;
const qnaMakerSearchName = `${qnaMakerServiceName}-search`.toLowerCase().replace('_', '');
const qnaMakerWebAppName = `${qnaMakerServiceName}-qnahost`.toLowerCase().replace('_', '');
const qnaMakerServicePlanName = `${qnaMakerServiceName}-serviceplan`;
// only support westus in qna
config.location = 'westus';
// deploy search service
const searchManagementClient = new SearchManagementClient(this.creds, this.subscriptionId, this.options);
const searchServiceDeployResult = await searchManagementClient.services.createOrUpdate(
config.resourceGroupName,
qnaMakerSearchName,
{
location: config.location,
sku: {
name: 'standard',
},
replicaCount: 1,
partitionCount: 1,
hostingMode: 'default',
}
);
if (searchServiceDeployResult._response.status >= 300) {
this.logger({
status: BotProjectDeployLoggerType.PROVISION_ERROR,
message: searchServiceDeployResult._response.bodyAsText,
});
throw createCustomizeError(ProvisionErrors.CREATE_QNA_ERROR, searchServiceDeployResult._response.bodyAsText);
}
// deploy websites
// Create new Service Plan or update the exisiting service plan created before
const webSiteManagementClient = new WebSiteManagementClient(this.creds, this.subscriptionId, this.options);
const servicePlanResult = await webSiteManagementClient.appServicePlans.createOrUpdate(
config.resourceGroupName,
qnaMakerServicePlanName,
{
location: config.location,
sku: {
name: 'S1',
tier: 'Standard',
size: 'S1',
family: 'S',
capacity: 1,
},
}
);
if (servicePlanResult._response.status >= 300) {
this.logger({
status: BotProjectDeployLoggerType.PROVISION_ERROR,
message: servicePlanResult._response.bodyAsText,
});
throw createCustomizeError(ProvisionErrors.CREATE_QNA_ERROR, servicePlanResult._response.bodyAsText);
}
// deploy or update exisiting app insights component
const applicationInsightsManagementClient = new ApplicationInsightsManagementClient(
this.creds,
this.subscriptionId,
this.options
);
const appinsightsName = config.resourceGroupName;
const appinsightsDeployResult = await applicationInsightsManagementClient.components.createOrUpdate(
config.resourceGroupName,
appinsightsName,
{
location: config.location,
applicationType: 'web',
kind: 'web',
}
);
if (appinsightsDeployResult._response.status >= 300 || appinsightsDeployResult.provisioningState != 'Succeeded') {
this.logger({
status: BotProjectDeployLoggerType.PROVISION_ERROR,
message: appinsightsDeployResult._response.bodyAsText,
});
throw createCustomizeError(ProvisionErrors.CREATE_QNA_ERROR, appinsightsDeployResult._response.bodyAsText);
}
// add web config for websites
const azureSearchAdminKey = (
await searchManagementClient.adminKeys.get(config.resourceGroupName, qnaMakerSearchName)
).primaryKey;
const appInsightsComponent = await applicationInsightsManagementClient.components.get(
config.resourceGroupName,
appinsightsName
);
const userAppInsightsKey = appInsightsComponent.instrumentationKey;
const userAppInsightsName = appinsightsName;
const userAppInsightsAppId = appInsightsComponent.appId;
const primaryEndpointKey = `${qnaMakerWebAppName}-PrimaryEndpointKey`;
const secondaryEndpointKey = `${qnaMakerWebAppName}-SecondaryEndpointKey`;
const defaultAnswer = 'No good match found in KB.';
const QNAMAKER_EXTENSION_VERSION = 'latest';
const EnableMultipleTestIndex = 'true';
// deploy qna host webapp
const webAppResult = await webSiteManagementClient.webApps.createOrUpdate(
config.resourceGroupName,
qnaMakerWebAppName,
{
name: qnaMakerWebAppName,
serverFarmId: servicePlanResult.name,
location: config.location,
siteConfig: {
cors: {
allowedOrigins: ['*'],
},
appSettings: [
{
name: 'AzureSearchName',
value: qnaMakerSearchName,
},
{
name: 'AzureSearchAdminKey',
value: azureSearchAdminKey,
},
{
name: 'UserAppInsightsKey',
value: userAppInsightsKey,
},
{
name: 'UserAppInsightsName',
value: userAppInsightsName,
},
{
name: 'UserAppInsightsAppId',
value: userAppInsightsAppId,
},
{
name: 'PrimaryEndpointKey',
value: primaryEndpointKey,
},
{
name: 'SecondaryEndpointKey',
value: secondaryEndpointKey,
},
{
name: 'DefaultAnswer',
value: defaultAnswer,
},
{
name: 'QNAMAKER_EXTENSION_VERSION',
value: QNAMAKER_EXTENSION_VERSION,
},
{
name: 'EnableMultipleTestIndex',
value: EnableMultipleTestIndex,
},
],
},
enabled: true,
}
);
if (webAppResult._response.status >= 300) {
this.logger({
status: BotProjectDeployLoggerType.PROVISION_ERROR,
message: webAppResult._response.bodyAsText,
});
throw createCustomizeError(ProvisionErrors.CREATE_QNA_ERROR, webAppResult._response.bodyAsText);
}
// Create qna account
const cognitiveServicesManagementClient = new CognitiveServicesManagementClient(
this.creds,
this.subscriptionId,
this.options
);
const deployResult = await cognitiveServicesManagementClient.accounts.create(
config.resourceGroupName,
qnaMakerServiceName,
{
kind: 'QnAMaker',
sku: {
name: config.sku ?? 'S0',
},
location: config.location,
properties: {
apiProperties: {
qnaRuntimeEndpoint: `https://${webAppResult.hostNames?.[0]}`,
},
},
}
);
if (deployResult._response.status >= 300) {
this.logger({
status: BotProjectDeployLoggerType.PROVISION_ERROR,
message: deployResult._response.bodyAsText,
});
throw createCustomizeError(ProvisionErrors.CREATE_QNA_ERROR, deployResult._response.bodyAsText);
}
const endpoint = webAppResult.hostNames?.[0];
const keys = await cognitiveServicesManagementClient.accounts.listKeys(
config.resourceGroupName,
qnaMakerServiceName
);
const subscriptionKey = keys?.key1 ?? '';
return {
endpoint: endpoint,
subscriptionKey: subscriptionKey,
};
} catch (err) {
this.logger({
status: BotProjectDeployLoggerType.PROVISION_ERROR,
message: JSON.stringify(err, Object.getOwnPropertyNames(err)),
});
throw createCustomizeError(ProvisionErrors.CREATE_QNA_ERROR, stringifyError(err));
}
}