From 4b7d29ded22239d9daaa49591032035fd2161a46 Mon Sep 17 00:00:00 2001 From: Rodrigo Rodriguez Date: Sun, 26 May 2019 20:25:08 -0300 Subject: [PATCH] fix(core.gbapp): Self-replication on Azure. --- .../admin.gbapp/services/GBAdminService.ts | 8 ++ .../dialogs/StartDialog.ts | 8 +- .../services/AzureDeployerService.ts | 99 +++++++++++++++---- .../core.gbapp/services/GBConfigService.ts | 8 +- packages/core.gbapp/services/GBDeployer.ts | 3 +- src/app.ts | 1 + 6 files changed, 97 insertions(+), 30 deletions(-) diff --git a/packages/admin.gbapp/services/GBAdminService.ts b/packages/admin.gbapp/services/GBAdminService.ts index a3a481d1..4f125057 100644 --- a/packages/admin.gbapp/services/GBAdminService.ts +++ b/packages/admin.gbapp/services/GBAdminService.ts @@ -63,6 +63,14 @@ export class GBAdminService implements IGBAdminService { return msRestAzure.generateUuid(); } + public static getNodeVersion() { + const packageJson = urlJoin(process.cwd(), 'package.json'); + // tslint:disable-next-line: non-literal-require + const pjson = require(packageJson); + + return pjson.engines.node.replace('=', ''); + } + public static async getADALTokenFromUsername(username: string, password: string) { const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password); diff --git a/packages/azuredeployer.gbapp/dialogs/StartDialog.ts b/packages/azuredeployer.gbapp/dialogs/StartDialog.ts index ad28b267..af203f11 100644 --- a/packages/azuredeployer.gbapp/dialogs/StartDialog.ts +++ b/packages/azuredeployer.gbapp/dialogs/StartDialog.ts @@ -100,8 +100,6 @@ export class StartDialog { authoringKey = this.retrieveAuthoringKey(); } - process.stdout.write(`${GBAdminService.GB_PROMPT}Thank you. That is enough information.\nNow building farm...`); - // Prepares the first instance on bot farm. const instance = {}; @@ -158,12 +156,12 @@ cannot start or end with or contain consecutive dashes and having 4 to 42 charac if (authoringKey === undefined) { process.stdout.write( `${ - GBAdminService.GB_PROMPT + GBAdminService.GB_PROMPT }Due to this opened issue: https://github.com/Microsoft/botbuilder-tools/issues/550\n` ); process.stdout.write( `${ - GBAdminService.GB_PROMPT + GBAdminService.GB_PROMPT }Please enter your LUIS Authoring Key, get it here: https://www.luis.ai/user/settings and paste it to me:` ); authoringKey = scanf('%s').replace(/(\n|\r)+$/, ''); @@ -206,7 +204,7 @@ generate manually an App ID and App Secret.\n` map[index++] = element; }); let subscriptionIndex; - if (!subscriptionIndex) { + if (!subscriptionIndex && subscriptionId === undefined) { process.stdout.write('CLOUD_SUBSCRIPTIONID (type a number):'); subscriptionIndex = scanf('%d'); subscriptionId = map[subscriptionIndex].subscriptionId; diff --git a/packages/azuredeployer.gbapp/services/AzureDeployerService.ts b/packages/azuredeployer.gbapp/services/AzureDeployerService.ts index 9db77874..74d204cf 100644 --- a/packages/azuredeployer.gbapp/services/AzureDeployerService.ts +++ b/packages/azuredeployer.gbapp/services/AzureDeployerService.ts @@ -42,7 +42,7 @@ import { SearchManagementClient } from 'azure-arm-search'; import { SqlManagementClient } from 'azure-arm-sql'; import { WebSiteManagementClient } from 'azure-arm-website'; //tslint:disable-next-line:no-submodule-imports -import { AppServicePlan } from 'azure-arm-website/lib/models'; +import { AppServicePlan, Site, SiteConfigResource, SiteSourceControl, SiteLogsConfig } from 'azure-arm-website/lib/models'; import { GBLog, IGBInstallationDeployer, IGBInstance } from 'botlib'; import { HttpHeaders, HttpMethods, ServiceClient, WebResource } from 'ms-rest-js'; import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService'; @@ -51,6 +51,9 @@ import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigS import { GBDeployer } from '../../../packages/core.gbapp/services/GBDeployer'; const Spinner = require('cli-spinner').Spinner; +// tslint:disable-next-line: no-submodule-imports +import * as simplegit from 'simple-git/promise'; +const git = simplegit(); // tslint:disable-next-line:no-submodule-imports import { CognitiveServicesAccount } from 'azure-arm-cognitiveservices/lib/models'; @@ -230,7 +233,6 @@ export class AzureDeployerService implements IGBInstallationDeployer { } } - public async updateBotProxy(botId, group, endpoint) { const baseUrl = `https://management.azure.com/`; const username = GBConfigService.get('CLOUD_USERNAME'); @@ -260,7 +262,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { } public async updateBot(botId: string, group: string, name: string, - description: string, endpoint: string, iconUrl: string) { + description: string, endpoint: string) { const baseUrl = `https://management.azure.com/`; const username = GBConfigService.get('CLOUD_USERNAME'); const password = GBConfigService.get('CLOUD_PASSWORD'); @@ -328,20 +330,16 @@ export class AzureDeployerService implements IGBInstallationDeployer { GBLog.info(`Deploying Bot Server...`); const serverFarm = await this.createHostingPlan(name, `${name}-server-plan`, instance.cloudLocation); - await this.createServer(serverFarm.id, name, `${name}-server`, instance.cloudLocation); + const serverName = `${name}-server`; + await this.createServer(serverFarm.id, name, serverName, instance.cloudLocation); GBLog.info(`Deploying Bot Storage...`); const administratorLogin = `sa${GBAdminService.getRndReadableIdentifier()}`; const administratorPassword = GBAdminService.getRndPassword(); const storageServer = `${name.toLowerCase()}-storage-server`; const storageName = `${name}-storage`; - await this.createStorageServer( - name, - storageServer, - administratorLogin, - administratorPassword, - storageServer, - instance.cloudLocation + await this.createStorageServer(name, storageServer, administratorLogin, + administratorPassword, storageServer, instance.cloudLocation ); await this.createStorage(name, storageServer, storageName, instance.cloudLocation); instance.storageUsername = administratorLogin; @@ -407,6 +405,9 @@ export class AzureDeployerService implements IGBInstallationDeployer { instance.cloudSubscriptionId ); + GBLog.info('Updating server environment variables...'); + await this.updateWebisteConfig(name, serverName, serverFarm.id, instance); + spinner.stop(); return instance; @@ -536,7 +537,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { fullyQualifiedDomainName: `${serverName}.database.windows.net` }; - return this.storageClient.servers.createOrUpdate(group, name, params); + return await this.storageClient.servers.createOrUpdate(group, name, params); } private async registerProviders(subscriptionId, baseUrl, accessToken) { @@ -604,7 +605,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { location: location }; - return this.searchClient.services.createOrUpdate(group, name, params); + return await this.searchClient.services.createOrUpdate(group, name, params); } private async createStorage(group, serverName, name, location) { @@ -614,7 +615,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { location: location }; - return this.storageClient.databases.createOrUpdate(group, serverName, name, params); + return await this.storageClient.databases.createOrUpdate(group, serverName, name, params); } private async createCognitiveServices(group, name, location, kind): Promise { @@ -648,7 +649,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { private async createDeployGroup(name, location) { const params = { location: location }; - return this.resourceClient.resourceGroups.createOrUpdate(name, params); + return await this.resourceClient.resourceGroups.createOrUpdate(name, params); } private async createHostingPlan(group, name, location): Promise { @@ -662,15 +663,75 @@ export class AzureDeployerService implements IGBInstallationDeployer { } }; - return this.webSiteClient.appServicePlans.createOrUpdate(group, name, params); + return await this.webSiteClient.appServicePlans.createOrUpdate(group, name, params); } private async createServer(farmId, group, name, location) { - const parameters = { + const parameters: Site = { location: location, - serverFarmId: farmId + serverFarmId: farmId, + + siteConfig: { + netFrameworkVersion + nodeVersion: GBAdminService.getNodeVersion(), + detailedErrorLoggingEnabled: true, + requestTracingEnabled: true + } + }; + const server = await this.webSiteClient.webApps.createOrUpdate(group, name, parameters); + + const siteLogsConfig: SiteLogsConfig = { + applicationLogs: { + fileSystem: { level: 'Error' } + } + }; + await this.webSiteClient.webApps.updateDiagnosticLogsConfig(group, name, siteLogsConfig); + + await this.webSiteClient.webApps.update + + const souceControlConfig: SiteSourceControl = { + repoUrl: 'https://github.com/GeneralBots/BotServer.git', + branch: 'master', + isManualIntegration: true, + isMercurial: false, + deploymentRollbackEnabled: false }; - return this.webSiteClient.webApps.createOrUpdate(group, name, parameters); + await this.webSiteClient.webApps.createOrUpdateSourceControl(group, name, souceControlConfig); + // await this.webSiteClient.webApps.syncRepository(name, name); + + return server; } + + private async updateWebisteConfig(group, name, serverFarmId, instance: IGBInstance) { + + const parameters: Site = { + location: instance.cloudLocation, + serverFarmId: serverFarmId, + siteConfig: { + appSettings: [ + { name: 'WEBSITE_NODE_DEFAULT_VERSION', value: GBAdminService.getNodeVersion() }, + { name: 'ADDITIONAL_DEPLOY_PATH', value: `` }, + { name: 'ADMIN_PASS', value: `${instance.adminPass}` }, + { name: 'CLOUD_SUBSCRIPTIONID', value: `${instance.cloudSubscriptionId}` }, + { name: 'CLOUD_LOCATION', value: `${instance.cloudLocation}` }, + { name: 'CLOUD_GROUP', value: `${instance.botId}` }, + { name: 'CLOUD_USERNAME', value: `${instance.cloudUsername}` }, + { name: 'CLOUD_PASSWORD', value: `${instance.cloudPassword}` }, + { name: 'MARKETPLACE_ID', value: `${instance.marketplaceId}` }, + { name: 'MARKETPLACE_SECRET', value: `${instance.marketplacePassword}` }, + { name: 'NLP_AUTHORING_KEY', value: `${instance.nlpAuthoringKey}` }, + { name: 'STORAGE_DIALECT', value: `${instance.storageDialect}` }, + { name: 'STORAGE_SERVER', value: `${instance.storageServer}.database.windows.net` }, + { name: 'STORAGE_NAME', value: `${instance.storageName}` }, + { name: 'STORAGE_USERNAME', value: `${instance.storageUsername}` }, + { name: 'STORAGE_PASSWORD', value: `${instance.storagePassword}` }, + { name: 'STORAGE_SYNC', value: `true` }] + + } + }; + + return await this.webSiteClient.webApps.createOrUpdate(group, name, parameters); + } + } diff --git a/packages/core.gbapp/services/GBConfigService.ts b/packages/core.gbapp/services/GBConfigService.ts index 6f635b76..07e07108 100644 --- a/packages/core.gbapp/services/GBConfigService.ts +++ b/packages/core.gbapp/services/GBConfigService.ts @@ -42,15 +42,15 @@ import { GBLog } from 'botlib'; * Base configuration for the server like storage. */ export class GBConfigService { - public static getServerPort(): number { + public static getServerPort(): string { if (process.env.PORT) { - return Number(process.env.PORT); + return process.env.PORT; } if (process.env.port) { - return Number(process.env.port); + return process.env.port; } - return 4242; + return '4242'; } public static init(): any { diff --git a/packages/core.gbapp/services/GBDeployer.ts b/packages/core.gbapp/services/GBDeployer.ts index 484fd5d1..3409daca 100644 --- a/packages/core.gbapp/services/GBDeployer.ts +++ b/packages/core.gbapp/services/GBDeployer.ts @@ -183,8 +183,7 @@ export class GBDeployer { accessToken, instance.title, instance.description, - proxyAddress, - '' + proxyAddress ); } else { diff --git a/src/app.ts b/src/app.ts index 46160535..3361d704 100644 --- a/src/app.ts +++ b/src/app.ts @@ -72,6 +72,7 @@ export class GBServer { public static run() { GBLog.info(`The Bot Server is in STARTING mode...`); + process.env.PWD = process.cwd(); // Creates a basic HTTP server that will serve several URL, one for each // bot instance.