@kumologica/builder
Version:
Kumologica build and deploy module
164 lines (133 loc) • 5.28 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const chalk = require('chalk');
const { codegen } = require('..');
/**
* sample events:
* https://docs.aws.amazon.com/lambda/latest/dg/lambda-services.html
*/
class AzureDeployer {
constructor(log) {
if (log) {
this.logger = log;
}
}
log(text, calog = true) {
if (this.logger) {
this.logger(text, calog);
} else {
console.log(text);
}
}
prepareEvn(params) {
let env = process.env;
env["ARM_CLIENT_ID"] = params.alias.client_id;
env["ARM_CLIENT_SECRET"] = params.alias.client_secret;
env["ARM_SUBSCRIPTION_ID"] = params.alias.subscription_id;
env["ARM_TENANT_ID"] = params.alias.tenant_id;
env["TF_IN_AUTOMATION"] = "true";
return env;
}
async import(id, ref, buildDir, env) {
const npmCmd = `terraform import ${id} ${ref}`;
try {
const response = await exec(npmCmd, { cwd: buildDir, env: env });
this.logCmdResponse(response);
this.log(` Import successful for:`);
this.log(` id: ${id}`);
this.log(` reference: ${ref}`);
} catch (Error) {
this.log(`--${Error.message.includes("Cannot import non-existent remote object")}`);
this.log(`--${Error.message}--`);
if (Error.message.includes("Cannot import non-existent remote object")) {
// swallow non-existent errors, this is first run
return;
}
this.log(` ${Error}`);
this.log(` Import failed:`);
this.log(` id: ${id}`);
this.log(` reference: ${ref}`);
throw Error;
}
}
logCmdResponse(response) {
if (response && process.env.KUMOLOGICA_LOGLEVEL && process.env.KUMOLOGICA_LOGLEVEL === 'debug') {
this.log('', false);
const lines = response.stdout.split('\n');
for (var i = 0; i < lines.length; i++) {
if (lines[i]) {
this.log(lines[i], false);
}
}
this.log('', false);
}
}
async runTerraform(buildDir, params) {
this.log(`Running terraform init ...`);
let env = this.prepareEvn(params);
let npmCmd = `terraform init`;
let response = await exec(npmCmd, { cwd: buildDir, env: env });
this.logCmdResponse(response);
this.log(`Running terraform import ...`);
const resourceGroupName = params["resource-group-name"] || `${params["azure-application-name"]}-resource-group`;
await this.import(
"azurerm_resource_group.resource_group",
`/subscriptions/${params.alias.subscription_id}/resourceGroups/${resourceGroupName}`,
buildDir, env);
await this.import(
"azurerm_application_insights.application_insights",
`/subscriptions/${params.alias.subscription_id}/resourceGroups/${resourceGroupName}/providers/microsoft.insights/components/${params["azure-application-name"]}-application-insights`,
buildDir, env);
const servicePlan = params["service-plan-id"] || `${params["azure-application-name"]}-app-service-plan`;
await this.import(
"azurerm_app_service_plan.app_service_plan",
`/subscriptions/${params.alias.subscription_id}/resourceGroups/${resourceGroupName}/providers/Microsoft.Web/serverfarms/${servicePlan}`,
buildDir, env);
await this.import(
"azurerm_function_app.function_app",
`/subscriptions/${params.alias.subscription_id}/resourceGroups/${resourceGroupName}/providers/Microsoft.Web/sites/${params["azure-application-name"]}`,
buildDir, env);
this.log(`Running terraform apply ...`);
npmCmd = `terraform apply -auto-approve`;
try {
response = await exec(npmCmd, { cwd: buildDir, env: env });
this.logCmdResponse(response);
this.log(chalk.whiteBright(`Function has been succesfully deployed`));
} catch (Error) {
this.log(`${Error}`);
this.log(`Deployment failed`);
throw Error;
}
}
extractListeners(buildDir, argv) {
const AdmZip = require('adm-zip');
const zipFfile = new AdmZip(path.join(buildDir, argv["zip-file-name"]));
const tmpDir = path.join(buildDir, 'tmp');
fs.ensureDir(tmpDir);
zipFfile.extractEntryTo('package.json', tmpDir);
const pck = codegen.loadJsonFile(path.join(tmpDir, 'package.json'));
const flowFileName = pck.files.find(f => f.endsWith('-flow.json'));
zipFfile.extractEntryTo(flowFileName, tmpDir);
const flow = codegen.loadJsonFile(path.join(tmpDir, flowFileName));
fs.rmdir(tmpDir, { recursive: true });
const functionName = flowFileName.replace('.json', '');
const url = `https://${argv["azure-application-name"]}.azurewebsites.net/${functionName}`;
const listener = flow.filter(i => i.type === "EventListener" && i.provider === 'azure');
this.log('');
this.log('Http Enpoints:');
listener.forEach(a => this.log(` ${(' ' + a.zapiMethod.toUpperCase()).slice(-6)} ${url}${a.zapiUrl}`), this);
}
async deploy(argv) {
let projectDir = argv["project-directory"] || process.cwd();
let buildDir = path.join(projectDir, 'build');
this.log(` project directory: ${projectDir}`);
this.log(` template file name: ${argv["template-file-name"]}`);
this.log(` zip file name: ${argv["zip-file-name"]}`);
this.log(` application name: ${argv["azure-application-name"]}`);
await this.runTerraform(buildDir, argv);
this.extractListeners(buildDir, argv);
}
}
module.exports = AzureDeployer;