Skip to content

Commit

Permalink
fix(startup): Startup improved and more checks added.
Browse files Browse the repository at this point in the history
  • Loading branch information
rodrigorodriguez committed Dec 18, 2018
1 parent 8490f5e commit 5d6c60e
Show file tree
Hide file tree
Showing 6 changed files with 462 additions and 436 deletions.
4 changes: 4 additions & 0 deletions packages/admin.gbapp/dialogs/AdminDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export class AdminDialog extends IGBDialog {
public static async deployPackageCommand(min: GBMinInstance, text: string, deployer: GBDeployer) {
const packageName = text.split(' ')[1];
const additionalPath = GBConfigService.get('ADDITIONAL_DEPLOY_PATH');
if (!additionalPath)
{
throw new Error('ADDITIONAL_DEPLOY_PATH is not set and deployPackage was called.');
}
await deployer.deployPackageFromLocalPath(min, UrlJoin(additionalPath, packageName));
}

Expand Down
4 changes: 2 additions & 2 deletions packages/azuredeployer.gbapp/services/AzureDeployerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ export class AzureDeployerService extends GBService {
instance.storageServer = storageServer;

logger.info(`Deploying Search...`);
const searchName = `${name}-search`;
const searchName = `${name}-search`.toLowerCase();
await this.createSearch(name, searchName, instance.cloudLocation);
const searchKeys = await this.searchClient.adminKeys.get(
name,
Expand Down Expand Up @@ -473,7 +473,7 @@ export class AzureDeployerService extends GBService {
const retrieveBotId = () => {
if (!botId) {
process.stdout.write(
`${GBAdminService.GB_PROMPT}Bot Id must only contain lowercase letters, digits or dashes, cannot start or end with or contain consecutive dashes and is limited from 4 to 42 characters long.\n`
`${GBAdminService.GB_PROMPT}Choose a unique bot Id containing lowercase letters, digits or dashes (cannot use dash as the first two or last one characters), cannot start or end with or contain consecutive dashes and having 4 to 42 characters long.\n`
);
process.stdout.write(`${GBAdminService.GB_PROMPT}BOT_ID:`);
botId = scanf('%s').replace(/(\n|\r)+$/, ''); // TODO: Update this regexp to match description of it.
Expand Down
31 changes: 16 additions & 15 deletions packages/core.gbapp/services/GBCoreService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,21 +218,22 @@ export class GBCoreService implements IGBCoreService {

public async writeEnv(instance: IGBInstance) {
const env = `ADDITIONAL_DEPLOY_PATH=
ADMIN_PASS=${instance.adminPass}
CLOUD_SUBSCRIPTIONID=${instance.cloudSubscriptionId}
CLOUD_LOCATION=${instance.cloudLocation}
CLOUD_GROUP=${instance.botId}
CLOUD_USERNAME=${instance.cloudUsername}
CLOUD_PASSWORD=${instance.cloudPassword}
MARKETPLACE_ID=${instance.marketplaceId}
MARKETPLACE_SECRET=${instance.marketplacePassword}
NLP_AUTHORING_KEY=${instance.nlpAuthoringKey}
STORAGE_DIALECT=${instance.storageDialect}
STORAGE_SERVER=${instance.storageServer}.database.windows.net
STORAGE_NAME=${instance.storageName}
STORAGE_USERNAME=${instance.storageUsername}
STORAGE_PASSWORD=${instance.storagePassword}
STORAGE_SYNC=true`;
ADMIN_PASS=${instance.adminPass}
CLOUD_SUBSCRIPTIONID=${instance.cloudSubscriptionId}
CLOUD_LOCATION=${instance.cloudLocation}
CLOUD_GROUP=${instance.botId}
CLOUD_USERNAME=${instance.cloudUsername}
CLOUD_PASSWORD=${instance.cloudPassword}
MARKETPLACE_ID=${instance.marketplaceId}
MARKETPLACE_SECRET=${instance.marketplacePassword}
NLP_AUTHORING_KEY=${instance.nlpAuthoringKey}
STORAGE_DIALECT=${instance.storageDialect}
STORAGE_SERVER=${instance.storageServer}.database.windows.net
STORAGE_NAME=${instance.storageName}
STORAGE_USERNAME=${instance.storageUsername}
STORAGE_PASSWORD=${instance.storagePassword}
STORAGE_SYNC=true
`;

fs.writeFileSync('.env', env);
}
Expand Down
215 changes: 120 additions & 95 deletions packages/core.gbapp/services/GBDeployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ const express = require('express');
const child_process = require('child_process');

import { GBMinInstance, IGBCoreService, IGBInstance } from 'botlib';
import { GBError } from 'botlib';
import { IGBPackage } from 'botlib';
import { GBError,IGBPackage } from 'botlib';
import { AzureSearch } from 'pragmatismo-io-framework';
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
import { GuaribasInstance, GuaribasPackage } from '../models/GBModel';
import { KBService } from './../../kb.gbapp/services/KBService';
import { GBConfigService } from './GBConfigService';
import { GBCoreService } from './GBCoreService';
import { GBImporter } from './GBImporterService';
import { GBVMService } from './GBVMService';

Expand All @@ -77,9 +77,10 @@ export class GBDeployer {
*
* Performs package deployment in all .gbai or default.
*
* */
public deployPackages(core: IGBCoreService, server: any, appPackages: IGBPackage[]) {
*/
public async deployPackages(core: IGBCoreService, server: any, appPackages: IGBPackage[]) {
const _this = this;

return new Promise(
(resolve: any, reject: any): any => {
let totalPackages = 0;
Expand Down Expand Up @@ -121,106 +122,30 @@ export class GBDeployer {
doIt(e);
});

/** Deploys all .gbapp files first. */

let appPackagesProcessed = 0;

gbappPackages.forEach(e => {
// Skips .gbapp inside deploy folder.
if (!e.startsWith('packages')) {
logger.info(`Deploying app: ${e}...`);
import(e)
.then(m => {
const p = new m.Package();
p.loadPackage(core, core.sequelize);
appPackages.push(p);
logger.info(`App (.gbapp) deployed: ${e}.`);
appPackagesProcessed++;
})
.catch(err => {
logger.error(`Error deploying App (.gbapp): ${e}: ${err}`);
appPackagesProcessed++;
});
} else {
appPackagesProcessed++;
}
});
// Deploys all .gbapp files first.

const appPackagesProcessed = this.deployAppPackages(gbappPackages, core, appPackages);

WaitUntil()
.interval(1000)
.times(10)
.condition(function(cb) {
.condition(cb => {
logger.info(`Waiting for app package deployment...`);
cb(appPackagesProcessed == gbappPackages.length);
cb(appPackagesProcessed === gbappPackages.length);
})
.done(async result => {
logger.info(`App Package deployment done.`);

try {
await core.syncDatabaseStructure();
} catch (e) {
throw e;
}

/** Deploys all .gbot files first. */

botPackages.forEach(e => {
if (e !== 'packages\\boot.gbot') {
logger.info(`Deploying bot: ${e}...`);
_this.deployBot(e);
logger.info(`Bot: ${e} deployed...`);
}
});

/** Then all remaining generalPackages are loaded. */

generalPackages = generalPackages.filter(p => !p.endsWith('.git'));

generalPackages.forEach(filename => {
const filenameOnly = Path.basename(filename);
logger.info(`Deploying package: ${filename}...`);

/** Handles apps for general bots - .gbapp must stay out of deploy folder. */

if (Path.extname(filename) === '.gbapp' || Path.extname(filename) === '.gblib') {
/** Themes for bots. */
} else if (Path.extname(filename) === '.gbtheme') {
server.use('/themes/' + filenameOnly, express.static(filename));
logger.info(`Theme (.gbtheme) assets accessible at: ${'/themes/' + filenameOnly}.`);

/** Knowledge base for bots. */
} else if (Path.extname(filename) === '.gbkb') {
server.use('/kb/' + filenameOnly + '/subjects', express.static(UrlJoin(filename, 'subjects')));
logger.info(`KB (.gbkb) assets accessible at: ${'/kb/' + filenameOnly}.`);
} else if (Path.extname(filename) === '.gbui') {
// Already Handled
} else if (Path.extname(filename) === '.gbdialog') {
// Already Handled
} else {
/** Unknown package format. */
const err = new Error(`Package type not handled: ${filename}.`);
reject(err);
}
totalPackages++;
});

WaitUntil()
.interval(100)
.times(5)
.condition(function(cb) {
logger.info(`Waiting for package deployment...`);
cb(totalPackages == generalPackages.length);
})
.done(function(result) {
if (botPackages.length === 0) {
logger.info(
'No external packages to load, please use ADDITIONAL_DEPLOY_PATH to point to a .gbai package folder.'
);
} else {
logger.info(`Package deployment done.`);
}
resolve();
});
({ generalPackages, totalPackages } = await this.deployDataPackages(
core,
botPackages,
_this,
generalPackages,
server,
reject,
totalPackages,
resolve
));
});
}
);
Expand Down Expand Up @@ -363,9 +288,109 @@ export class GBDeployer {
public installDefaultGBUI() {
const root = 'packages/default.gbui';
if (!Fs.existsSync(`${root}/build`)) {
logger.info(`Preparing default.gbui (it may take some additional time for the first time)...`);
Fs.writeFileSync(`${root}/.env`, 'SKIP_PREFLIGHT_CHECK=true');
child_process.execSync('npm install', { cwd: root });
child_process.execSync('npm run build', { cwd: root });
}
}

private async deployDataPackages(
core: GBCoreService,
botPackages: string[],
_this: this,
generalPackages: string[],
server: any,
reject: any,
totalPackages: number,
resolve: any
) {
try {
await core.syncDatabaseStructure();
} catch (e) {
throw e;
}

// Deploys all .gbot files first.

botPackages.forEach(e => {
if (e !== 'packages\\boot.gbot') {
logger.info(`Deploying bot: ${e}...`);
_this.deployBot(e);
logger.info(`Bot: ${e} deployed...`);
}
});

// Then all remaining generalPackages are loaded.

generalPackages = generalPackages.filter(p => !p.endsWith('.git'));
generalPackages.forEach(filename => {
const filenameOnly = Path.basename(filename);
logger.info(`Deploying package: ${filename}...`);

// Handles apps for general bots - .gbapp must stay out of deploy folder.

if (Path.extname(filename) === '.gbapp' || Path.extname(filename) === '.gblib') {
// Themes for bots.
} else if (Path.extname(filename) === '.gbtheme') {
server.use('/themes/' + filenameOnly, express.static(filename));
logger.info(`Theme (.gbtheme) assets accessible at: ${'/themes/' + filenameOnly}.`);
} else if (Path.extname(filename) === '.gbkb') {
server.use('/kb/' + filenameOnly + '/subjects', express.static(UrlJoin(filename, 'subjects')));
logger.info(`KB (.gbkb) assets accessible at: ${'/kb/' + filenameOnly}.`);
} else if (Path.extname(filename) === '.gbui') {
// Already Handled
} else if (Path.extname(filename) === '.gbdialog') {
// Already Handled
} else {
// Unknown package format.
const err = new Error(`Package type not handled: ${filename}.`);
reject(err);
}
totalPackages++;
});

WaitUntil()
.interval(100)
.times(5)
.condition(cb => {
logger.info(`Waiting for package deployment...`);
cb(totalPackages === generalPackages.length);
})
.done(result => {
if (botPackages.length === 0) {
logger.info('Use ADDITIONAL_DEPLOY_PATH to point to a .gbai package folder (no external packages).');
} else {
logger.info(`Package deployment done.`);
}
resolve();
});

return { generalPackages, totalPackages };
}

private deployAppPackages(gbappPackages: string[], core: any, appPackages: any[]) {
let appPackagesProcessed = 0;
gbappPackages.forEach(e => {
// Skips .gbapp inside deploy folder.
if (!e.startsWith('packages')) {
logger.info(`Deploying app: ${e}...`);
import(e)
.then(m => {
const p = new m.Package();
p.loadPackage(core, core.sequelize);
appPackages.push(p);
logger.info(`App (.gbapp) deployed: ${e}.`);
appPackagesProcessed++;
})
.catch(err => {
logger.error(`Error deploying App (.gbapp): ${e}: ${err}`);
appPackagesProcessed++;
});
} else {
appPackagesProcessed++;
}
});
return appPackagesProcessed;
}
}
Loading

0 comments on commit 5d6c60e

Please sign in to comment.