UNPKG

@kumologica/builder

Version:
164 lines (133 loc) 5.28 kB
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;