UNPKG

sleeveforarm

Version:
237 lines 12.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const FS = require("fs-extra"); const Path = require("path"); // tslint:disable-next-line:max-line-length const ApplicationInsightsInfrastructure = require("./applicationInsightsInfrastructure"); const CommonUtilities = require("./common-utilities"); const data = require("./data"); const promiseGate_1 = require("./promiseGate"); const Resource = require("./resource"); const ServiceEnvironment = require("./serviceEnvironmentUtilities"); const webapp_node_azure_1 = require("./webapp-node-azure"); class BaseDeployWebappNodeAzureInfrastructure { constructor(nodeInfra) { this.nodeInfra = nodeInfra; } getDeployedURL() { return __awaiter(this, void 0, void 0, function* () { // tslint:disable-next-line:max-line-length const azResult = yield CommonUtilities.runAzCommand(`az webapp show \ --resource-group ${this.nodeInfra.resourceGroup.resourceGroupName} \ --name ${this.nodeInfra.webAppDNSName}`); return "http://" + azResult.defaultHostName; }); } } exports.BaseDeployWebappNodeAzureInfrastructure = BaseDeployWebappNodeAzureInfrastructure; class WebappNodeAzureInfrastructure extends webapp_node_azure_1.default { constructor() { super(...arguments); this.promiseGate = new promiseGate_1.default(); } initialize(resource, targetDirectoryPath) { super.initialize(resource, targetDirectoryPath); if (resource !== null) { Object.assign(this, resource); } return this; } setup() { return __awaiter(this, void 0, void 0, function* () { return yield webapp_node_azure_1.default.internalSetup(__filename, this.targetDirectoryPath, data.data.WebAppNameLength); }); } hydrate(resourcesInEnvironment, deploymentType) { const _super = name => super[name]; return __awaiter(this, void 0, void 0, function* () { yield _super("hydrate").call(this, resourcesInEnvironment, deploymentType); if (this.webAppDNSName === undefined) { this.webAppDNSName = this.resourceGroup.resourceGroupName + this.baseName; } if (this.webAppServicePlanName === undefined) { this.webAppServicePlanName = this.resourceGroup.resourceGroupName + this.baseName + "webAppPlan"; } return this; }); } deployResource(developmentDeploy = false) { return __awaiter(this, void 0, void 0, function* () { yield this.resourceGroup.getBaseDeployClassInstance(); const aiResource = CommonUtilities.findGlobalDefaultResourceByType(this.resourcesInEnvironment, ApplicationInsightsInfrastructure .ApplicationInsightsInfrastructure); const aiKeyID = (yield aiResource.getBaseDeployClassInstance()).getInstrumentationKey(); const storageResources = CommonUtilities.findInfraResourcesByInterface(this.resourcesInEnvironment, CommonUtilities.isIStorageResource); const storagePromisesToWaitFor = []; for (const storageResource of storageResources) { storagePromisesToWaitFor .push(storageResource.getBaseDeployClassInstance()); } yield (this.deploymentType === Resource.DeployType.Production ? this.deployToProduction(developmentDeploy, storagePromisesToWaitFor, aiKeyID) : this.deployToDev(storagePromisesToWaitFor, aiKeyID)); this.promiseGate .openGateSuccess(new BaseDeployWebappNodeAzureInfrastructure(this)); return this; }); } getBaseDeployClassInstance() { return this.promiseGate.promise.then(function (baseClass) { return baseClass; }); } deployToDev(storagePromisesToWaitFor, aiKeyId) { return __awaiter(this, void 0, void 0, function* () { const baseStorageResources = yield Promise.all(storagePromisesToWaitFor); let environmentVariablesArray = []; for (const baseStorageResource of baseStorageResources) { environmentVariablesArray = [...environmentVariablesArray, ...baseStorageResource.getEnvironmentVariables()]; } environmentVariablesArray.push([ServiceEnvironment.aiEnvironmentVariableName, aiKeyId]); const sleevePath = CommonUtilities.localScratchDirectory(this.targetDirectoryPath); yield FS.ensureDir(sleevePath); const variablePath = Path.join(CommonUtilities .localScratchDirectory(this.targetDirectoryPath), ServiceEnvironment.environmentFileName); FS.removeSync(variablePath); for (const nameValuePair of environmentVariablesArray) { FS.appendFileSync(variablePath, `${nameValuePair[0]} ${nameValuePair[1]}\n`); } }); } deployToProduction(developmentDeploy, storagePromisesToWaitFor, aiKeyId) { return __awaiter(this, void 0, void 0, function* () { const resourceGroupName = this.resourceGroup.resourceGroupName; const webPromise = CommonUtilities.runAzCommand(`az appservice plan create \ --name ${this.webAppServicePlanName} \ --resource-group ${resourceGroupName} --sku FREE`) .then(() => { return CommonUtilities.runAzCommand(`az webapp create \ --name ${this.webAppDNSName} \ --resource-group ${resourceGroupName} \ --plan ${this.webAppServicePlanName}`, CommonUtilities.azCommandOutputs.json); }); const webAppCreateResult = yield webPromise; const baseStorageResources = yield Promise.all(storagePromisesToWaitFor); let environmentVariablesArray = []; const secondStepPromises = []; const webAppIPs = webAppCreateResult.outboundIpAddresses.split(","); for (const baseStorageResource of baseStorageResources) { webAppIPs.forEach((ipAddr) => { secondStepPromises.push(baseStorageResource .setFirewallRule(this.baseName, ipAddr)); }); environmentVariablesArray = [...environmentVariablesArray, ...baseStorageResource.getEnvironmentVariables()]; } let environmentalVariables = ""; for (const variablePair of environmentVariablesArray) { environmentalVariables += `${variablePair[0]}=${variablePair[1]} `; } environmentalVariables += `${ServiceEnvironment.aiEnvironmentVariableName}=${aiKeyId}`; if (environmentalVariables !== "") { secondStepPromises.push(CommonUtilities.runAzCommand(`az webapp config appsettings set \ --name ${this.webAppDNSName} \ --resource-group ${this.resourceGroup.resourceGroupName} \ --settings ${environmentalVariables}`)); } yield Promise.all(secondStepPromises); yield CommonUtilities.runAzCommand(`az webapp deployment source config-local-git \ --name ${this.webAppDNSName} --resource-group ${resourceGroupName} \ --query url --output tsv`, CommonUtilities.azCommandOutputs.string); yield this.deployToWebApp(developmentDeploy); }); } /** * Handles copying the local web app code to Azure * @developmentDeploy This is only used for development of sleeveforarm, * it lets us know we need to deploy to the webapp a development version * of sleeveforarm. */ deployToWebApp(developmentDeploy = false) { return __awaiter(this, void 0, void 0, function* () { const resourceGroupName = this.resourceGroup.resourceGroupName; const profiles = yield CommonUtilities.runAzCommand(`az webapp deployment list-publishing-profiles --name ${this.webAppDNSName} \ --resource-group ${resourceGroupName}`); const msDeployProfile = profiles.find((profile) => profile.publishMethod === "MSDeploy"); if (msDeployProfile === undefined) { throw new Error("We didn't find the MSDeploy profile, huh?"); } const username = msDeployProfile.userName; const password = msDeployProfile.userPWD; const gitURL = // tslint:disable-next-line:max-line-length `https://${username}:${password}@${this.webAppDNSName}.scm.azurewebsites.net/${this.webAppDNSName}.git`; const gitCloneDepotParentPath = CommonUtilities.localScratchDirectory(this.targetDirectoryPath); const gitCloneDepotPath = Path.join(gitCloneDepotParentPath, this.webAppDNSName); yield FS.emptyDir(gitCloneDepotParentPath); yield CommonUtilities.retryAfterFailure(() => __awaiter(this, void 0, void 0, function* () { return yield CommonUtilities.exec(`git clone ${gitURL}`, gitCloneDepotParentPath); }), 60); const directoryContents = yield FS.readdir(gitCloneDepotPath); // It's a git depo so it always has a hidden .git file, hence there // will be at least one file if (directoryContents.length > 1) { // This command fails if there isn't at least one file (other than // .git) in the directory, hence why we have the check above. yield CommonUtilities.exec("git rm -f -r -q *", gitCloneDepotPath); } const nodeModulesPath = Path.join(this.targetDirectoryPath, "node_modules"); const sleevePath = Path.join(this.targetDirectoryPath, ".sleeve"); yield FS.copy(this.targetDirectoryPath, gitCloneDepotPath, { filter: (src) => (src !== nodeModulesPath && src !== sleevePath) }); if (developmentDeploy) { yield this.developDeployToWebApp(gitCloneDepotPath); } yield CommonUtilities.exec("git add -A", gitCloneDepotPath); const result = yield CommonUtilities.exec("git status --porcelain=v2", gitCloneDepotPath); if (result.stdout !== "") { yield CommonUtilities.exec("git commit -am \"Prep for release\"", gitCloneDepotPath); yield CommonUtilities.exec("git push", gitCloneDepotPath); } }); } /** * Deploys a development version of SleeveForArm */ developDeployToWebApp(gitCloneDepotPath) { return __awaiter(this, void 0, void 0, function* () { // We want to clone node_modules in this case so we need to // get rid of .gitignore yield FS.remove(Path.join(gitCloneDepotPath, ".gitignore")); const sleeveForArmClonePath = Path.join(gitCloneDepotPath, "sleeveforarm"); yield FS.ensureDir(sleeveForArmClonePath); const depotPath = Path.join(__dirname, ".."); const disposableTestFilesPath = Path.join(depotPath, "disposableTestFiles"); const nodeModulesPath = Path.join(depotPath, "node_modules"); yield FS.copy(depotPath, sleeveForArmClonePath, { filter: (src) => (src !== disposableTestFilesPath) && (src !== nodeModulesPath) }); // Need to make the node module files just look like regular files // Otherwise the WebApp Git Repo will treat sleeveforarm as a // sub-module and not properly copy it over. yield FS.remove(Path.join(sleeveForArmClonePath, ".git")); // Otherwise we won't check in any of the .js or other files we normally // ignore. yield FS.remove(Path.join(sleeveForArmClonePath, ".gitignore")); }); } } exports.WebappNodeAzureInfrastructure = WebappNodeAzureInfrastructure; //# sourceMappingURL=webapp-node-azureInfrastructure.js.map