ARM automation done.
This commit is contained in:
parent
d030ed8278
commit
b7f256b01f
7 changed files with 408 additions and 293 deletions
|
@ -69,7 +69,7 @@ Notes:
|
||||||
|
|
||||||
1. Create/Edit the .env file and add the ADDITIONAL_DEPLOY_PATH key pointing to the .gbai local parent folder of .gbapp, .gbot, .gbtheme, .gbkb package directories.
|
1. Create/Edit the .env file and add the ADDITIONAL_DEPLOY_PATH key pointing to the .gbai local parent folder of .gbapp, .gbot, .gbtheme, .gbkb package directories.
|
||||||
2. Specify STORAGE_SYNC to TRUE so database sync is run when the server is run.
|
2. Specify STORAGE_SYNC to TRUE so database sync is run when the server is run.
|
||||||
3. In case of Microsoft SQL Server add the following keys: STORAGE_HOST, STORAGE_NAME, STORAGE_USERNAME, STORAGE_PASSWORD, STORAGE_DIALECT to `mssql`.
|
3. In case of Microsoft SQL Server add the following keys: STORAGE_SERVER, STORAGE_NAME, STORAGE_USERNAME, STORAGE_PASSWORD, STORAGE_DIALECT to `mssql`.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
|
|
||||||
|
|
|
@ -42,12 +42,12 @@ import { SqlManagementClient } from "azure-arm-sql";
|
||||||
import { CognitiveServicesManagementClient } from "azure-arm-cognitiveservices";
|
import { CognitiveServicesManagementClient } from "azure-arm-cognitiveservices";
|
||||||
import { CognitiveServicesAccount } from "azure-arm-cognitiveservices/lib/models";
|
import { CognitiveServicesAccount } from "azure-arm-cognitiveservices/lib/models";
|
||||||
import { SearchManagementClient } from "azure-arm-search";
|
import { SearchManagementClient } from "azure-arm-search";
|
||||||
import { WebResource, ServiceClient } from "ms-rest-js";
|
import { WebResource, ServiceClient, HttpMethods } from "ms-rest-js";
|
||||||
import * as simplegit from "simple-git/promise";
|
import * as simplegit from "simple-git/promise";
|
||||||
import { AppServicePlan } from "azure-arm-website/lib/models";
|
import { AppServicePlan } from "azure-arm-website/lib/models";
|
||||||
import { GBConfigService } from "../../../deploy/core.gbapp/services/GBConfigService";
|
import { GBConfigService } from "../../../deploy/core.gbapp/services/GBConfigService";
|
||||||
|
|
||||||
const Spinner = require('cli-spinner').Spinner;
|
const Spinner = require("cli-spinner").Spinner;
|
||||||
const scanf = require("scanf");
|
const scanf = require("scanf");
|
||||||
const msRestAzure = require("ms-rest-azure");
|
const msRestAzure = require("ms-rest-azure");
|
||||||
const git = simplegit();
|
const git = simplegit();
|
||||||
|
@ -56,6 +56,7 @@ const UrlJoin = require("url-join");
|
||||||
const PasswordGenerator = require("strict-password-generator").default;
|
const PasswordGenerator = require("strict-password-generator").default;
|
||||||
const iconUrl =
|
const iconUrl =
|
||||||
"https://github.com/pragmatismo-io/BotServer/blob/master/docs/images/generalbots-logo-squared.png";
|
"https://github.com/pragmatismo-io/BotServer/blob/master/docs/images/generalbots-logo-squared.png";
|
||||||
|
const publicIp = require("public-ip");
|
||||||
|
|
||||||
export class AzureDeployerService extends GBService {
|
export class AzureDeployerService extends GBService {
|
||||||
instance: IGBInstance;
|
instance: IGBInstance;
|
||||||
|
@ -70,9 +71,279 @@ export class AzureDeployerService extends GBService {
|
||||||
location: string;
|
location: string;
|
||||||
public subscriptionId: string;
|
public subscriptionId: string;
|
||||||
static apiVersion = "2017-12-01";
|
static apiVersion = "2017-12-01";
|
||||||
|
farmName: any;
|
||||||
|
|
||||||
|
public static async getSubscriptions(credentials) {
|
||||||
|
let subscriptionClient = new SubscriptionClient.default(credentials);
|
||||||
|
return subscriptionClient.subscriptions.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deployFarm(proxyAddress: string): Promise<IGBInstance> {
|
||||||
|
let culture = "en-us";
|
||||||
|
|
||||||
|
// Tries do get information from .env file otherwise asks in command-line.
|
||||||
|
let instance: IGBInstance = {};
|
||||||
|
instance = await this.ensureConfiguration(instance);
|
||||||
|
|
||||||
|
let spinner = new Spinner("%s");
|
||||||
|
spinner.start();
|
||||||
|
spinner.setSpinnerString("|/-\\");
|
||||||
|
|
||||||
|
let keys: any;
|
||||||
|
let name = instance.botId;
|
||||||
|
|
||||||
|
logger.info(`Deploying Deploy Group (It may take a few minutes)...`);
|
||||||
|
await this.createDeployGroup(name, instance.cloudLocation);
|
||||||
|
|
||||||
|
logger.info(`Deploying Bot Server...`);
|
||||||
|
let serverFarm = await this.createHostingPlan(
|
||||||
|
name,
|
||||||
|
`${name}-server-plan`,
|
||||||
|
instance.cloudLocation
|
||||||
|
);
|
||||||
|
await this.createServer(
|
||||||
|
serverFarm.id,
|
||||||
|
name,
|
||||||
|
`${name}-server`,
|
||||||
|
instance.cloudLocation
|
||||||
|
);
|
||||||
|
|
||||||
|
let administratorLogin = AzureDeployerService.getRndAdminAccount();
|
||||||
|
let administratorPassword = AzureDeployerService.getRndPassword();
|
||||||
|
|
||||||
|
logger.info(`Deploying Bot Storage...`);
|
||||||
|
let storageServer = `${name}-storage-server`;
|
||||||
|
let storageName = `${name}-storage`;
|
||||||
|
await this.createStorageServer(
|
||||||
|
name,
|
||||||
|
storageServer,
|
||||||
|
administratorLogin,
|
||||||
|
administratorPassword,
|
||||||
|
storageServer,
|
||||||
|
instance.cloudLocation
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.createStorage(
|
||||||
|
name,
|
||||||
|
storageServer,
|
||||||
|
storageName,
|
||||||
|
instance.cloudLocation
|
||||||
|
);
|
||||||
|
instance.storageUsername = administratorLogin;
|
||||||
|
instance.storagePassword = administratorPassword;
|
||||||
|
instance.storageName = storageName;
|
||||||
|
instance.storageDialect = "mssql";
|
||||||
|
instance.storageServer = storageServer;
|
||||||
|
|
||||||
|
logger.info(`Deploying Search...`);
|
||||||
|
let searchName = `${name}-search`;
|
||||||
|
await this.createSearch(name, searchName, instance.cloudLocation);
|
||||||
|
let searchKeys = await this.searchClient.queryKeys.listBySearchService(
|
||||||
|
name,
|
||||||
|
searchName
|
||||||
|
);
|
||||||
|
instance.searchHost = `${searchName}.search.windows.net`;
|
||||||
|
instance.searchIndex = "azuresql-index";
|
||||||
|
instance.searchIndexer = "azuresql-indexer";
|
||||||
|
instance.searchKey = searchKeys[0].key;
|
||||||
|
|
||||||
|
logger.info(`Deploying Speech...`);
|
||||||
|
let speech = await this.createSpeech(
|
||||||
|
name,
|
||||||
|
`${name}-speech`,
|
||||||
|
instance.cloudLocation
|
||||||
|
);
|
||||||
|
keys = await this.cognitiveClient.accounts.listKeys(name, speech.name);
|
||||||
|
instance.speechKeyEndpoint = speech.endpoint;
|
||||||
|
instance.speechKey = keys.key1;
|
||||||
|
|
||||||
|
logger.info(`Deploying SpellChecker...`);
|
||||||
|
let spellChecker = await this.createSpellChecker(
|
||||||
|
name,
|
||||||
|
`${name}-spellchecker`,
|
||||||
|
instance.cloudLocation
|
||||||
|
);
|
||||||
|
keys = await this.cognitiveClient.accounts.listKeys(
|
||||||
|
name,
|
||||||
|
spellChecker.name
|
||||||
|
);
|
||||||
|
instance.spellCheckerKey = keys.key1;
|
||||||
|
instance.spellCheckerEndpoint = spellChecker.endpoint;
|
||||||
|
|
||||||
|
logger.info(`Deploying Text Analytics...`);
|
||||||
|
let textAnalytics = await this.createTextAnalytics(
|
||||||
|
name,
|
||||||
|
`${name}-textanalytics`,
|
||||||
|
instance.cloudLocation
|
||||||
|
);
|
||||||
|
keys = await this.cognitiveClient.accounts.listKeys(
|
||||||
|
name,
|
||||||
|
textAnalytics.name
|
||||||
|
);
|
||||||
|
instance.textAnalyticsEndpoint = textAnalytics.endpoint;
|
||||||
|
instance.textAnalyticsKey = keys.key1;
|
||||||
|
|
||||||
|
logger.info(`Deploying NLP...`);
|
||||||
|
let nlp = await this.createNLP(name, `${name}-nlp`, instance.cloudLocation);
|
||||||
|
keys = await this.cognitiveClient.accounts.listKeys(name, nlp.name);
|
||||||
|
let nlpAppId = await this.createLUISApp(
|
||||||
|
name,
|
||||||
|
name,
|
||||||
|
instance.cloudLocation,
|
||||||
|
culture,
|
||||||
|
instance.nlpAuthoringKey
|
||||||
|
);
|
||||||
|
let appId = msRestAzure.generateUuid();
|
||||||
|
instance.nlpEndpoint = nlp.endpoint;
|
||||||
|
instance.nlpKey = keys.key1;
|
||||||
|
instance.nlpAppId = nlpAppId;
|
||||||
|
|
||||||
|
logger.info(`Deploying Bot...`);
|
||||||
|
instance = await this.deployBootBot(
|
||||||
|
instance,
|
||||||
|
name,
|
||||||
|
`${proxyAddress}/api/messages/${name}`,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
instance.cloudSubscriptionId,
|
||||||
|
appId
|
||||||
|
);
|
||||||
|
|
||||||
|
spinner.stop();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async openStorageFirewall(groupName, serverName) {
|
||||||
|
let username = GBConfigService.get("CLOUD_USERNAME");
|
||||||
|
let password = GBConfigService.get("CLOUD_PASSWORD");
|
||||||
|
let subscriptionId = GBConfigService.get("CLOUD_SUBSCRIPTIONID");
|
||||||
|
|
||||||
|
let credentials = await msRestAzure.loginWithUsernamePassword(
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
);
|
||||||
|
|
||||||
|
let ip = await publicIp.v4();
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
startIpAddress: ip,
|
||||||
|
endIpAddress: ip
|
||||||
|
};
|
||||||
|
|
||||||
|
let storageClient = new SqlManagementClient(credentials, subscriptionId);
|
||||||
|
await storageClient.firewallRules.createOrUpdate(
|
||||||
|
groupName,
|
||||||
|
serverName,
|
||||||
|
"gb",
|
||||||
|
params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ensureConfiguration(instance: IGBInstance) {
|
||||||
|
let username = GBConfigService.get("CLOUD_USERNAME");
|
||||||
|
let password = GBConfigService.get("CLOUD_PASSWORD");
|
||||||
|
let subscriptionId = GBConfigService.get("CLOUD_SUBSCRIPTIONID");
|
||||||
|
let location = GBConfigService.get("CLOUD_LOCATION");
|
||||||
|
let botId = GBConfigService.get("BOT_ID");
|
||||||
|
|
||||||
|
// No .env so asks for cloud credentials to start a new farm.
|
||||||
|
if (!username || !password || !subscriptionId || !location || !botId) {
|
||||||
|
process.stdout.write(
|
||||||
|
"A empty enviroment is detected. Please, enter details:"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let retriveUsername = () => {
|
||||||
|
if (!username) {
|
||||||
|
process.stdout.write("CLOUD_USERNAME:");
|
||||||
|
username = scanf("%s");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let retrivePassword = () => {
|
||||||
|
if (!password) {
|
||||||
|
process.stdout.write("CLOUD_PASSWORD:");
|
||||||
|
password = scanf("%s");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let retrieveBotId = () => {
|
||||||
|
if (!botId) {
|
||||||
|
process.stdout.write(
|
||||||
|
"Bot Id must only contain lowercase letters, digits or dashes, cannot start or end with or contain consecutive dashes and is limited to 60 characters.\n"
|
||||||
|
);
|
||||||
|
process.stdout.write("BOT_ID:");
|
||||||
|
botId = scanf("%s");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let authoringKey = GBConfigService.get("NLP_AUTHORING_KEY");
|
||||||
|
let retriveAuthoringKey = () => {
|
||||||
|
if (!authoringKey) {
|
||||||
|
process.stdout.write(
|
||||||
|
"Due to this opened issue: https://github.com/Microsoft/botbuilder-tools/issues/550\n"
|
||||||
|
);
|
||||||
|
process.stdout.write("Please enter your LUIS Authoring Key:");
|
||||||
|
authoringKey = scanf("%s");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
while (!authoringKey) {
|
||||||
|
retriveAuthoringKey();
|
||||||
|
}
|
||||||
|
while (!botId) {
|
||||||
|
retrieveBotId();
|
||||||
|
}
|
||||||
|
while (!username) {
|
||||||
|
retriveUsername();
|
||||||
|
}
|
||||||
|
while (!password) {
|
||||||
|
retrivePassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connects to the cloud and retrives subscriptions.
|
||||||
|
|
||||||
|
let credentials = await msRestAzure.loginWithUsernamePassword(
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
);
|
||||||
|
if (!subscriptionId) {
|
||||||
|
let map = {};
|
||||||
|
let index = 1;
|
||||||
|
let list = await AzureDeployerService.getSubscriptions(credentials);
|
||||||
|
list.forEach(element => {
|
||||||
|
console.log(
|
||||||
|
`${index}: ${element.displayName} (${element.subscriptionId})`
|
||||||
|
);
|
||||||
|
map[index++] = element;
|
||||||
|
});
|
||||||
|
let subscriptionIndex;
|
||||||
|
let retrieveSubscription = () => {
|
||||||
|
if (!subscriptionIndex) {
|
||||||
|
process.stdout.write("CLOUD_SUBSCRIPTIONID (type a number):");
|
||||||
|
subscriptionIndex = scanf("%d");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
while (!subscriptionIndex) {
|
||||||
|
retrieveSubscription();
|
||||||
|
}
|
||||||
|
subscriptionId = map[subscriptionIndex].subscriptionId;
|
||||||
|
}
|
||||||
|
let retriveLocation = () => {
|
||||||
|
if (!location) {
|
||||||
|
process.stdout.write("CLOUD_LOCATION:");
|
||||||
|
location = scanf("%s");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
while (!location) {
|
||||||
|
retriveLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepares the first instance on bot farm.
|
||||||
|
|
||||||
|
instance.botId = botId;
|
||||||
|
instance.cloudUsername = username;
|
||||||
|
instance.cloudPassword = password;
|
||||||
|
instance.cloudSubscriptionId = subscriptionId;
|
||||||
|
instance.cloudLocation = location;
|
||||||
|
instance.nlpAuthoringKey = authoringKey;
|
||||||
|
instance.adminPass = AzureDeployerService.getRndPassword();
|
||||||
|
|
||||||
constructor(credentials, subscriptionId, location) {
|
|
||||||
super();
|
|
||||||
this.resourceClient = new ResourceManagementClient.default(
|
this.resourceClient = new ResourceManagementClient.default(
|
||||||
credentials,
|
credentials,
|
||||||
subscriptionId
|
subscriptionId
|
||||||
|
@ -86,134 +357,9 @@ export class AzureDeployerService extends GBService {
|
||||||
credentials,
|
credentials,
|
||||||
subscriptionId
|
subscriptionId
|
||||||
);
|
);
|
||||||
|
|
||||||
this.searchClient = new SearchManagementClient(credentials, subscriptionId);
|
this.searchClient = new SearchManagementClient(credentials, subscriptionId);
|
||||||
this.accessToken = credentials.tokenCache._entries[0].accessToken;
|
this.accessToken = credentials.tokenCache._entries[0].accessToken;
|
||||||
this.location = location;
|
|
||||||
this.subscriptionId = subscriptionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async getSubscriptions(credentials) {
|
|
||||||
let subscriptionClient = new SubscriptionClient.default(credentials);
|
|
||||||
return subscriptionClient.subscriptions.list();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async deployFarm(
|
|
||||||
name: string,
|
|
||||||
location: string,
|
|
||||||
proxyAddress: string
|
|
||||||
): Promise<IGBInstance> {
|
|
||||||
let instance: any = {};
|
|
||||||
let culture = "en-us";
|
|
||||||
|
|
||||||
let spinner = new Spinner('%s');
|
|
||||||
spinner.start();
|
|
||||||
spinner.setSpinnerString("⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈");
|
|
||||||
|
|
||||||
let keys: any;
|
|
||||||
|
|
||||||
logger.info(`Deploying Deploy Group...`);
|
|
||||||
await this.createDeployGroup(name, location);
|
|
||||||
|
|
||||||
logger.info(`Deploying Bot Server...`);
|
|
||||||
let serverFarm = await this.createHostingPlan(
|
|
||||||
name,
|
|
||||||
`${name}-server-plan`,
|
|
||||||
location
|
|
||||||
);
|
|
||||||
await this.createServer(serverFarm.id, name, `${name}-server`, location);
|
|
||||||
|
|
||||||
let administratorLogin = AzureDeployerService.getRndAdminAccount();
|
|
||||||
let administratorPassword = AzureDeployerService.getRndPassword();
|
|
||||||
|
|
||||||
logger.info(`Deploying Bot Storage...`);
|
|
||||||
let storageServerName = `${name}-storage-server`;
|
|
||||||
await this.createStorageServer(
|
|
||||||
name,
|
|
||||||
storageServerName,
|
|
||||||
administratorLogin,
|
|
||||||
administratorPassword,
|
|
||||||
storageServerName,
|
|
||||||
location
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.createStorage(
|
|
||||||
name,
|
|
||||||
storageServerName,
|
|
||||||
`${name}-storage`,
|
|
||||||
location
|
|
||||||
);
|
|
||||||
instance.storageUsername = administratorLogin;
|
|
||||||
instance.storagePassword = administratorPassword;
|
|
||||||
instance.storageName = storageServerName;
|
|
||||||
instance.storageDialect = "mssql";
|
|
||||||
instance.storageServerName = storageServerName;
|
|
||||||
|
|
||||||
logger.info(`Deploying Search...`);
|
|
||||||
let searchName = `${name}-search`;
|
|
||||||
|
|
||||||
await this.createSearch(name, searchName, location);
|
|
||||||
let searchKeys = await this.searchClient.queryKeys.listBySearchService(
|
|
||||||
name,
|
|
||||||
searchName
|
|
||||||
);
|
|
||||||
instance.searchHost = `${searchName}.search.windows.net`;
|
|
||||||
instance.searchIndex = "azuresql-index";
|
|
||||||
instance.searchIndexer = "azuresql-indexer";
|
|
||||||
instance.searchKey = searchKeys[0].key;
|
|
||||||
|
|
||||||
logger.info(`Deploying NLP...`);
|
|
||||||
let nlp = await this.createNLP(name, `${name}-nlp`, location);
|
|
||||||
keys = await this.cognitiveClient.accounts.listKeys(name, nlp.name);
|
|
||||||
let nlpAppId = await this.createLUISApp(name, name, location, culture);
|
|
||||||
instance.nlpEndpoint = nlp.endpoint;
|
|
||||||
instance.nlpKey = keys.key1;
|
|
||||||
instance.nlpAppId = nlpAppId;
|
|
||||||
|
|
||||||
logger.info(`Deploying Speech...`);
|
|
||||||
let speech = await this.createSpeech(name, `${name}-speech`, location);
|
|
||||||
keys = await this.cognitiveClient.accounts.listKeys(name, speech.name);
|
|
||||||
instance.speechKeyEndpoint = speech.endpoint;
|
|
||||||
instance.speechKey = keys.key1;
|
|
||||||
|
|
||||||
logger.info(`Deploying SpellChecker...`);
|
|
||||||
let spellChecker = await this.createSpellChecker(
|
|
||||||
name,
|
|
||||||
`${name}-spellchecker`,
|
|
||||||
location
|
|
||||||
);
|
|
||||||
keys = await this.cognitiveClient.accounts.listKeys(
|
|
||||||
name,
|
|
||||||
spellChecker.name
|
|
||||||
);
|
|
||||||
instance.spellCheckerKey = keys.key1;
|
|
||||||
instance.spellCheckerEndpoint = spellChecker.endpoint;
|
|
||||||
|
|
||||||
logger.info(`Deploying Text Analytics...`);
|
|
||||||
let textAnalytics = await this.createTextAnalytics(
|
|
||||||
name,
|
|
||||||
`${name}-textanalytics`,
|
|
||||||
location
|
|
||||||
);
|
|
||||||
keys = await this.cognitiveClient.accounts.listKeys(
|
|
||||||
name,
|
|
||||||
textAnalytics.name
|
|
||||||
);
|
|
||||||
instance.textAnalyticsEndpoint = textAnalytics.endpoint;
|
|
||||||
instance.textAnalyticsKey = keys.key1;
|
|
||||||
|
|
||||||
let appId = msRestAzure.generateUuid();
|
|
||||||
logger.info(`Deploying Bot...`);
|
|
||||||
instance = await this.deployBootBot(
|
|
||||||
instance,
|
|
||||||
name,
|
|
||||||
`${proxyAddress}/api/messages/${name}`,
|
|
||||||
nlpAppId,
|
|
||||||
keys.key1,
|
|
||||||
this.subscriptionId,
|
|
||||||
appId
|
|
||||||
);
|
|
||||||
|
|
||||||
spinner.stop();
|
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
@ -227,10 +373,7 @@ export class AzureDeployerService extends GBService {
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
appId
|
appId
|
||||||
) {
|
) {
|
||||||
logger.info(`Deploying Bot...`);
|
|
||||||
|
|
||||||
let botId = name + AzureDeployerService.getRndBotId();
|
let botId = name + AzureDeployerService.getRndBotId();
|
||||||
|
|
||||||
[
|
[
|
||||||
instance.marketplacePassword,
|
instance.marketplacePassword,
|
||||||
instance.webchatKey
|
instance.webchatKey
|
||||||
|
@ -378,44 +521,59 @@ export class AzureDeployerService extends GBService {
|
||||||
name: string,
|
name: string,
|
||||||
description: string,
|
description: string,
|
||||||
location: string,
|
location: string,
|
||||||
culture: string
|
culture: string,
|
||||||
|
authoringKey: string
|
||||||
) {
|
) {
|
||||||
let parameters = {
|
let parameters = {
|
||||||
name: name,
|
name: name,
|
||||||
description: description,
|
description: description,
|
||||||
culture: culture
|
culture: culture
|
||||||
};
|
};
|
||||||
let requestUrl = `https://${location}.api.cognitive.microsoft.com/luis/api/v2.0/apps/`;
|
|
||||||
let req = new WebResource();
|
|
||||||
|
|
||||||
req.method = "POST";
|
let body = JSON.stringify(parameters);
|
||||||
req.url = requestUrl;
|
let apps = await this.makeNlpRequest(
|
||||||
|
location,
|
||||||
|
authoringKey,
|
||||||
|
null,
|
||||||
|
"GET",
|
||||||
|
"apps"
|
||||||
|
);
|
||||||
|
let app = (apps.bodyAsJson as any).filter(x => x.name == name)[0];
|
||||||
|
let id: string;
|
||||||
|
if (!app) {
|
||||||
|
let res = await this.makeNlpRequest(
|
||||||
|
location,
|
||||||
|
authoringKey,
|
||||||
|
body,
|
||||||
|
"POST",
|
||||||
|
"apps"
|
||||||
|
);
|
||||||
|
id = res.bodyAsText;
|
||||||
|
} else {
|
||||||
|
id = app.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async makeNlpRequest(
|
||||||
|
location: string,
|
||||||
|
authoringKey: string,
|
||||||
|
body: string,
|
||||||
|
method: HttpMethods,
|
||||||
|
resource: string
|
||||||
|
) {
|
||||||
|
let req = new WebResource();
|
||||||
|
req.method = method;
|
||||||
|
req.url = `https://${location}.api.cognitive.microsoft.com/luis/api/v2.0/${resource}`;
|
||||||
req.headers = {};
|
req.headers = {};
|
||||||
req.headers["Content-Type"] = "application/json";
|
req.headers["Content-Type"] = "application/json";
|
||||||
req.headers["accept-language"] = "*";
|
req.headers["accept-language"] = "*";
|
||||||
|
|
||||||
let authoringKey = GBConfigService.get("NLP_AUTHORING_KEY");
|
|
||||||
let retriveAuthoringKey = () => {
|
|
||||||
if (!authoringKey) {
|
|
||||||
process.stdout.write(
|
|
||||||
"Due to this opened issue: https://github.com/Microsoft/botbuilder-tools/issues/550\n"
|
|
||||||
);
|
|
||||||
process.stdout.write("Please enter your LUIS Authoring Key:");
|
|
||||||
authoringKey = scanf("%s");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while (!authoringKey) {
|
|
||||||
retriveAuthoringKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
req.headers["Ocp-Apim-Subscription-Key"] = authoringKey;
|
req.headers["Ocp-Apim-Subscription-Key"] = authoringKey;
|
||||||
req.body = JSON.stringify(parameters);
|
req.body = body;
|
||||||
|
|
||||||
let httpClient = new ServiceClient();
|
let httpClient = new ServiceClient();
|
||||||
let res = await httpClient.sendRequest(req);
|
let res = await httpClient.sendRequest(req);
|
||||||
|
return res;
|
||||||
return res.bodyAsJson;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createSearch(group, name, location) {
|
private async createSearch(group, name, location) {
|
||||||
|
@ -598,97 +756,13 @@ export class AzureDeployerService extends GBService {
|
||||||
lowerCaseAlpha: true,
|
lowerCaseAlpha: true,
|
||||||
number: true,
|
number: true,
|
||||||
specialCharacter: true,
|
specialCharacter: true,
|
||||||
minimumLength: 8,
|
minimumLength: 12,
|
||||||
maximumLength: 14
|
maximumLength: 14
|
||||||
};
|
};
|
||||||
let password = passwordGenerator.generatePassword(options);
|
let password = passwordGenerator.generatePassword(options);
|
||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async ensureDeployer() {
|
|
||||||
// Tries do get information from .env file otherwise asks in command-line.
|
|
||||||
|
|
||||||
let username = GBConfigService.get("CLOUD_USERNAME");
|
|
||||||
let password = GBConfigService.get("CLOUD_PASSWORD");
|
|
||||||
let subscriptionId = GBConfigService.get("CLOUD_SUBSCRIPTIONID");
|
|
||||||
let location = GBConfigService.get("CLOUD_LOCATION");
|
|
||||||
|
|
||||||
// No .env so asks for cloud credentials to start a new farm.
|
|
||||||
|
|
||||||
if (!username || !password || !subscriptionId || !location) {
|
|
||||||
process.stdout.write(
|
|
||||||
"FIRST RUN: A empty enviroment is detected. Please, enter credentials to create a new General Bots Farm."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let retriveUsername = () => {
|
|
||||||
if (!username) {
|
|
||||||
process.stdout.write("CLOUD_USERNAME:");
|
|
||||||
username = scanf("%s");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let retrivePassword = () => {
|
|
||||||
if (!password) {
|
|
||||||
process.stdout.write("CLOUD_PASSWORD:");
|
|
||||||
password = scanf("%s");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while (!username) {
|
|
||||||
retriveUsername();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!password) {
|
|
||||||
retrivePassword();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connects to the cloud and retrives subscriptions.
|
|
||||||
|
|
||||||
let credentials = await msRestAzure.loginWithUsernamePassword(
|
|
||||||
username,
|
|
||||||
password
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!subscriptionId) {
|
|
||||||
let map = {};
|
|
||||||
let index = 1;
|
|
||||||
let list = await AzureDeployerService.getSubscriptions(credentials);
|
|
||||||
list.forEach(element => {
|
|
||||||
console.log(
|
|
||||||
`${index}: ${element.displayName} (${element.subscriptionId})`
|
|
||||||
);
|
|
||||||
map[index++] = element;
|
|
||||||
});
|
|
||||||
|
|
||||||
let subscriptionIndex;
|
|
||||||
let retrieveSubscription = () => {
|
|
||||||
if (!subscriptionIndex) {
|
|
||||||
process.stdout.write("CLOUD_SUBSCRIPTIONID (type a number):");
|
|
||||||
subscriptionIndex = scanf("%d");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while (!subscriptionIndex) {
|
|
||||||
retrieveSubscription();
|
|
||||||
}
|
|
||||||
subscriptionId = map[subscriptionIndex].subscriptionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
let retriveLocation = () => {
|
|
||||||
if (!location) {
|
|
||||||
process.stdout.write("CLOUD_LOCATION:");
|
|
||||||
location = scanf("%s");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while (!location) {
|
|
||||||
retriveLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AzureDeployerService(credentials, subscriptionId, location);
|
|
||||||
}
|
|
||||||
|
|
||||||
static getKBSearchSchema(indexName) {
|
static getKBSearchSchema(indexName) {
|
||||||
return {
|
return {
|
||||||
name: indexName,
|
name: indexName,
|
||||||
|
|
|
@ -121,9 +121,15 @@ export class GuaribasInstance extends Model<GuaribasInstance>
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
cloudSubscriptionId: string;
|
cloudSubscriptionId: string;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
cloudUsername: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
cloudRegion: string;
|
cloudPassword: string;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
cloudLocation: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
whatsappBotKey: string;
|
whatsappBotKey: string;
|
||||||
|
@ -180,6 +186,12 @@ export class GuaribasInstance extends Model<GuaribasInstance>
|
||||||
@Column({ type: DataType.STRING(512) })
|
@Column({ type: DataType.STRING(512) })
|
||||||
nlpEndpoint: string;
|
nlpEndpoint: string;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
nlpAuthoringKey: string;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
deploymentPaths: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
searchHost: string;
|
searchHost: string;
|
||||||
|
|
||||||
|
@ -210,6 +222,9 @@ export class GuaribasInstance extends Model<GuaribasInstance>
|
||||||
@Column
|
@Column
|
||||||
storagePath: string;
|
storagePath: string;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
adminPass: string;
|
||||||
|
|
||||||
/* Settings section of bot.json */
|
/* Settings section of bot.json */
|
||||||
|
|
||||||
@Column(DataType.FLOAT)
|
@Column(DataType.FLOAT)
|
||||||
|
|
|
@ -50,12 +50,6 @@ export class GBConfigService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public writeEntry(name, value) {
|
|
||||||
if (fs.exists) {
|
|
||||||
fs.appendFileSync(".env", `${name}=${value}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static get(key: string): string | undefined {
|
static get(key: string): string | undefined {
|
||||||
let value = GBConfigService.tryGet(key);
|
let value = GBConfigService.tryGet(key);
|
||||||
|
|
||||||
|
@ -77,7 +71,7 @@ export class GBConfigService {
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case "STORAGE_DIALECT":
|
case "STORAGE_DIALECT":
|
||||||
value = "sqlite";
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case "STORAGE_STORAGE":
|
case "STORAGE_STORAGE":
|
||||||
value = "./guaribas.sqlite";
|
value = "./guaribas.sqlite";
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
const logger = require("../../../src/logger");
|
const logger = require("../../../src/logger");
|
||||||
import { Sequelize } from "sequelize-typescript";
|
import { Sequelize } from "sequelize-typescript";
|
||||||
|
import * as fs from "fs";
|
||||||
import { GBConfigService } from "./GBConfigService";
|
import { GBConfigService } from "./GBConfigService";
|
||||||
import { IGBInstance, IGBCoreService } from "botlib";
|
import { IGBInstance, IGBCoreService } from "botlib";
|
||||||
import { GuaribasInstance } from "../models/GBModel";
|
import { GuaribasInstance } from "../models/GBModel";
|
||||||
|
@ -49,14 +50,6 @@ export class GBCoreService implements IGBCoreService {
|
||||||
return GBConfigService.tryGet("STORAGE_DIALECT");
|
return GBConfigService.tryGet("STORAGE_DIALECT");
|
||||||
}
|
}
|
||||||
|
|
||||||
async ensureCloud(cloudDeployer) {
|
|
||||||
let instance = new GuaribasInstance();
|
|
||||||
await cloudDeployer.deploy(instance, "westus");
|
|
||||||
instance.save();
|
|
||||||
|
|
||||||
let content = `STORAGE_HOST = ${instance.storageServer}\n
|
|
||||||
STORAGE_NAME, STORAGE_USERNAME, STORAGE_PASSWORD, STORAGE_DIALECT`;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Data access layer instance.
|
* Data access layer instance.
|
||||||
*/
|
*/
|
||||||
|
@ -91,7 +84,6 @@ export class GBCoreService implements IGBCoreService {
|
||||||
* Constructor retrieves default values.
|
* Constructor retrieves default values.
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
this.dialect = GBConfigService.get("STORAGE_DIALECT");
|
|
||||||
this.adminService = new GBAdminService(this);
|
this.adminService = new GBAdminService(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +93,8 @@ export class GBCoreService implements IGBCoreService {
|
||||||
async initDatabase() {
|
async initDatabase() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
|
this.dialect = GBConfigService.get("STORAGE_DIALECT");
|
||||||
|
|
||||||
let host: string | undefined;
|
let host: string | undefined;
|
||||||
let database: string | undefined;
|
let database: string | undefined;
|
||||||
let username: string | undefined;
|
let username: string | undefined;
|
||||||
|
@ -108,12 +102,14 @@ export class GBCoreService implements IGBCoreService {
|
||||||
let storage: string | undefined;
|
let storage: string | undefined;
|
||||||
|
|
||||||
if (this.dialect === "mssql") {
|
if (this.dialect === "mssql") {
|
||||||
host = GBConfigService.get("STORAGE_HOST");
|
host = GBConfigService.get("STORAGE_SERVER");
|
||||||
database = GBConfigService.get("STORAGE_NAME");
|
database = GBConfigService.get("STORAGE_NAME");
|
||||||
username = GBConfigService.get("STORAGE_USERNAME");
|
username = GBConfigService.get("STORAGE_USERNAME");
|
||||||
password = GBConfigService.get("STORAGE_PASSWORD");
|
password = GBConfigService.get("STORAGE_PASSWORD");
|
||||||
} else if (this.dialect === "sqlite") {
|
} else if (this.dialect === "sqlite") {
|
||||||
storage = GBConfigService.get("STORAGE_STORAGE");
|
storage = GBConfigService.get("STORAGE_STORAGE");
|
||||||
|
} else {
|
||||||
|
reject(`Unknown dialect: ${this.dialect}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let logging =
|
let logging =
|
||||||
|
@ -302,11 +298,29 @@ export class GBCoreService implements IGBCoreService {
|
||||||
return GuaribasInstance.findOne(options);
|
return GuaribasInstance.findOne(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async writeEnv(instance: IGBInstance) {
|
||||||
|
let env =
|
||||||
|
`ADMIN_PASS=${instance.adminPass}\n` +
|
||||||
|
`ADDITIONAL_DEPLOY_PATH=\n` +
|
||||||
|
`STORAGE_DIALECT=${instance.storageDialect}\n` +
|
||||||
|
`STORAGE_SERVER=${instance.storageServer}.database.windows.net\n` +
|
||||||
|
`STORAGE_NAME=${instance.storageName}\n` +
|
||||||
|
`STORAGE_USERNAME=${instance.storageUsername}\n` +
|
||||||
|
`STORAGE_PASSWORD=${instance.storagePassword}\n`+
|
||||||
|
`CLOUD_USERNAME=${instance.cloudUsername}\n` +
|
||||||
|
`CLOUD_PASSWORD=${instance.cloudPassword}\n` +
|
||||||
|
`CLOUD_SUBSCRIPTIONID=${instance.cloudSubscriptionId}\n` +
|
||||||
|
`CLOUD_LOCATION=${instance.cloudLocation}\n` +
|
||||||
|
`CLOUD_GROUP=${instance.botId}\n` +
|
||||||
|
`NLP_AUTHORING_KEY=${instance.nlpAuthoringKey}`;
|
||||||
|
|
||||||
|
fs.writeFileSync(".env", env);
|
||||||
|
}
|
||||||
|
|
||||||
public async ensureProxy(): Promise<string> {
|
public async ensureProxy(): Promise<string> {
|
||||||
let proxyAddress: string;
|
let proxyAddress: string;
|
||||||
const ngrok = require('ngrok');
|
const ngrok = require("ngrok");
|
||||||
return await ngrok.connect();
|
return await ngrok.connect();
|
||||||
|
|
||||||
|
|
||||||
// let expiresOn = new Date(
|
// let expiresOn = new Date(
|
||||||
// await this.adminService.getValue(0, "proxyExpiresOn")
|
// await this.adminService.getValue(0, "proxyExpiresOn")
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
"express-promise-router": "3.0.3",
|
"express-promise-router": "3.0.3",
|
||||||
"fs-extra": "7.0.0",
|
"fs-extra": "7.0.0",
|
||||||
"fs-walk": "0.0.2",
|
"fs-walk": "0.0.2",
|
||||||
|
"ip": "^1.1.5",
|
||||||
"localize": "0.4.7",
|
"localize": "0.4.7",
|
||||||
"marked": "0.5.1",
|
"marked": "0.5.1",
|
||||||
"mocha": "5.2.0",
|
"mocha": "5.2.0",
|
||||||
|
@ -72,6 +73,7 @@
|
||||||
"ngrok": "^3.1.0",
|
"ngrok": "^3.1.0",
|
||||||
"pragmatismo-io-framework": "1.0.17",
|
"pragmatismo-io-framework": "1.0.17",
|
||||||
"process-exists": "^3.1.0",
|
"process-exists": "^3.1.0",
|
||||||
|
"public-ip": "^2.4.0",
|
||||||
"reflect-metadata": "0.1.12",
|
"reflect-metadata": "0.1.12",
|
||||||
"request-promise-native": "1.0.5",
|
"request-promise-native": "1.0.5",
|
||||||
"scanf": "^1.0.2",
|
"scanf": "^1.0.2",
|
||||||
|
@ -83,6 +85,7 @@
|
||||||
"swagger-client": "3.8.21",
|
"swagger-client": "3.8.21",
|
||||||
"tedious": "2.6.4",
|
"tedious": "2.6.4",
|
||||||
"ts-node": "7.0.1",
|
"ts-node": "7.0.1",
|
||||||
|
"tslint": "^5.11.0",
|
||||||
"typedoc": "0.13.0",
|
"typedoc": "0.13.0",
|
||||||
"typescript": "3.1.3",
|
"typescript": "3.1.3",
|
||||||
"url-join": "4.0.0",
|
"url-join": "4.0.0",
|
||||||
|
|
73
src/app.ts
73
src/app.ts
|
@ -53,7 +53,7 @@ import { GBCustomerSatisfactionPackage } from "../deploy/customer-satisfaction.g
|
||||||
import { GBAdminService } from "../deploy/admin.gbapp/services/GBAdminService";
|
import { GBAdminService } from "../deploy/admin.gbapp/services/GBAdminService";
|
||||||
import { GuaribasInstance } from "../deploy/core.gbapp/models/GBModel";
|
import { GuaribasInstance } from "../deploy/core.gbapp/models/GBModel";
|
||||||
import { AzureDeployerService } from "../deploy/azuredeployer.gbapp/services/AzureDeployerService";
|
import { AzureDeployerService } from "../deploy/azuredeployer.gbapp/services/AzureDeployerService";
|
||||||
import { IGBPackage } from "botlib";
|
import { IGBPackage, IGBInstance } from "botlib";
|
||||||
|
|
||||||
let appPackages = new Array<IGBPackage>();
|
let appPackages = new Array<IGBPackage>();
|
||||||
|
|
||||||
|
@ -61,13 +61,10 @@ let appPackages = new Array<IGBPackage>();
|
||||||
* General Bots open-core entry point.
|
* General Bots open-core entry point.
|
||||||
*/
|
*/
|
||||||
export class GBServer {
|
export class GBServer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program entry-point.
|
* Program entry-point.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static MASTERBOT_PREFIX = "generalbots-masterbot"
|
|
||||||
|
|
||||||
static run() {
|
static run() {
|
||||||
// Creates a basic HTTP server that will serve several URL, one for each
|
// Creates a basic HTTP server that will serve several URL, one for each
|
||||||
// bot instance. This allows the same server to attend multiple Bot on
|
// bot instance. This allows the same server to attend multiple Bot on
|
||||||
|
@ -85,6 +82,7 @@ export class GBServer {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let bootInstance: IGBInstance;
|
||||||
server.listen(port, () => {
|
server.listen(port, () => {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -94,21 +92,29 @@ export class GBServer {
|
||||||
|
|
||||||
GBConfigService.init();
|
GBConfigService.init();
|
||||||
let core = new GBCoreService();
|
let core = new GBCoreService();
|
||||||
|
|
||||||
// Ensures cloud / on-premises infrastructure is setup.
|
// Ensures cloud / on-premises infrastructure is setup.
|
||||||
|
|
||||||
logger.info(`Establishing a development local proxy...`);
|
logger.info(`Establishing a development local proxy...`);
|
||||||
let proxyAddress = await core.ensureProxy();
|
let proxyAddress = await core.ensureProxy();
|
||||||
logger.info(`Ensuring services availability...`);
|
|
||||||
let cloudDeployer = await AzureDeployerService.ensureDeployer();
|
try {
|
||||||
let instance = await cloudDeployer.deployFarm('gbot', 'westus', proxyAddress);
|
await core.initDatabase();
|
||||||
|
} catch (error) {
|
||||||
|
logger.info(`Deploying cognitive infrastructure...`);
|
||||||
|
let azureDeployer = new AzureDeployerService();
|
||||||
|
bootInstance = await azureDeployer.deployFarm(proxyAddress);
|
||||||
|
core.writeEnv(bootInstance);
|
||||||
|
logger.info(`File .env written, starting...`);
|
||||||
|
GBConfigService.init();
|
||||||
|
|
||||||
|
await core.initDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Get .gb* templates from GitHub and download do additional deploy folder.
|
// TODO: Get .gb* templates from GitHub and download do additional deploy folder.
|
||||||
|
|
||||||
await core.initDatabase();
|
|
||||||
|
|
||||||
// Check admin password.
|
// Check admin password.
|
||||||
|
|
||||||
let conversationalService = new GBConversationalService(core);
|
let conversationalService = new GBConversationalService(core);
|
||||||
let adminService = new GBAdminService(core);
|
let adminService = new GBAdminService(core);
|
||||||
let password = GBConfigService.get("ADMIN_PASS");
|
let password = GBConfigService.get("ADMIN_PASS");
|
||||||
|
@ -138,28 +144,37 @@ export class GBServer {
|
||||||
|
|
||||||
// Loads all bot instances from object storage, if it's formatted.
|
// Loads all bot instances from object storage, if it's formatted.
|
||||||
|
|
||||||
logger.info(`All instances are being now loaded...`);
|
logger.info(`Loading instances from storage...`);
|
||||||
let instances: GuaribasInstance[];
|
let instances: GuaribasInstance[];
|
||||||
try {
|
try {
|
||||||
instances = await core.loadInstances();
|
instances = await core.loadInstances();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Check if storage is empty and needs formatting.
|
if (error.parent.code === "ELOGIN") {
|
||||||
|
|
||||||
let isInvalidObject =
|
let azureDeployer = new AzureDeployerService();
|
||||||
error.parent.number == 208 || error.parent.errno == 1; // MSSQL or SQLITE.
|
let group = GBConfigService.get("CLOUD_GROUP")
|
||||||
|
let serverName = GBConfigService.get("STORAGE_SERVER").split(".database.windows.net")[0]
|
||||||
|
await azureDeployer.openStorageFirewall(group,serverName )
|
||||||
|
|
||||||
if (isInvalidObject) {
|
|
||||||
if (GBConfigService.get("STORAGE_SYNC") != "true") {
|
|
||||||
throw `Operating storage is out of sync or there is a storage connection error. Try setting STORAGE_SYNC to true in .env file. Error: ${
|
|
||||||
error.message
|
|
||||||
}.`;
|
|
||||||
} else {
|
|
||||||
logger.info(
|
|
||||||
`Storage is empty. After collecting storage structure from all .gbapps it will get synced.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw `Cannot connect to operating storage: ${error.message}.`;
|
// Check if storage is empty and needs formatting.
|
||||||
|
|
||||||
|
let isInvalidObject =
|
||||||
|
error.parent.number == 208 || error.parent.errno == 1; // MSSQL or SQLITE.
|
||||||
|
|
||||||
|
if (isInvalidObject) {
|
||||||
|
if (GBConfigService.get("STORAGE_SYNC") != "true") {
|
||||||
|
throw `Operating storage is out of sync or there is a storage connection error. Try setting STORAGE_SYNC to true in .env file. Error: ${
|
||||||
|
error.message
|
||||||
|
}.`;
|
||||||
|
} else {
|
||||||
|
logger.info(
|
||||||
|
`Storage is empty. After collecting storage structure from all .gbapps it will get synced.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw `Cannot connect to operating storage: ${error.message}.`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,11 +187,11 @@ export class GBServer {
|
||||||
// If instances is undefined here it's because storage has been formatted.
|
// If instances is undefined here it's because storage has been formatted.
|
||||||
// Load all instances from .gbot found on deploy package directory.
|
// Load all instances from .gbot found on deploy package directory.
|
||||||
if (!instances) {
|
if (!instances) {
|
||||||
|
let saveInstance = new GuaribasInstance(bootInstance);
|
||||||
|
saveInstance.save();
|
||||||
instances = await core.loadInstances();
|
instances = await core.loadInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
await core.ensureCloud(cloudDeployer);
|
|
||||||
|
|
||||||
// Setup server dynamic (per bot instance) resources and listeners.
|
// Setup server dynamic (per bot instance) resources and listeners.
|
||||||
|
|
||||||
logger.info(`Building instances.`);
|
logger.info(`Building instances.`);
|
||||||
|
|
Loading…
Add table
Reference in a new issue