UNPKG

mira

Version:

NearForm Accelerator for Cloud Native Serverless AWS

129 lines (117 loc) 4.38 kB
import { pascalCase } from 'change-case' import { parseDomain, fromUrl, ParseResultType } from 'parse-domain' import config from 'config' import _ from 'lodash' import AWS from 'aws-sdk' export interface RoleConfig { readonly profile: string readonly account: string readonly region: string } /** * It is important that we disallow undefined here, otherwise resource name collisions may occur * @internal */ export function nameResource (namespace: string, ...subNames: string[]): string { return [namespace, ...subNames].map(str => pascalCase(str + '')).join('-') } export interface EnvData { readonly name: string readonly profile: string readonly withDomain?: boolean readonly baseDomain?: string readonly webAppUrl?: string readonly requireManualApproval?: boolean readonly hostedZoneId?: 'string' } export interface Domain { readonly baseDomain: string readonly webAppUrl: string } /** * In developer mode build using a sub-domain of the base domain. Otherwise, parse the base domain from the web app URL. * @internal */ export function getUrl (envData: EnvData, isDeveloperMode: boolean, stackName: string): Domain { // If webAppUrl is specified, always prefer the given value. if (envData.webAppUrl) { if (envData.baseDomain) { throw new Error(`Cannot specify baseDomain when already given webAppUrl for ${envData.name}`) } let baseDomain const parsedDomain = parseDomain(fromUrl(envData.webAppUrl)) if (parsedDomain.type === ParseResultType.Listed) { baseDomain = `${parsedDomain.domain}.${parsedDomain.topLevelDomains.join('.')}` } else if (parsedDomain.type === ParseResultType.NotListed) { console.warn(`The webAppUrl url '${envData.webAppUrl}' domain is not listed.`) baseDomain = `${parsedDomain.labels.slice(-2).join('.')}` } else { throw new Error(`Is not possible to extract baseDomain from the webAppUrl '${envData.webAppUrl}'`) } return { baseDomain, webAppUrl: envData.webAppUrl } } // Outside of developer mode, webAppUrl is required. if (!isDeveloperMode) { throw new Error(`No webAppUrl set for ${envData.name}`) } // In developer mode, baseDomain is required. if (!envData.baseDomain) { throw new Error(`No baseDomain set for ${envData.name}`) } // In developer mode, webAppUrl will be generated unless it is specified in the config. const subdomain = stackName.toLowerCase() const webAppUrl = `${subdomain}.${envData.baseDomain}` return { baseDomain: envData.baseDomain, webAppUrl } } /** * FIXME: maybe there is a less hacky way to do this? * https://stackoverflow.com/questions/44433527/how-to-load-config-from-aws-config * @internal */ export function loadAWSProfile (profile: string): RoleConfig { // temporarily override const cleanups = [] cleanups.push(overrideEnv('AWS_PROFILE', profile)) cleanups.push(overrideEnv('AWS_SDK_LOAD_CONFIG', 'true')) // load const credentials = new AWS.SharedIniFileCredentials({ profile }) const awsConfig = new AWS.Config({ credentials }) // cleanup for (const cleanup of cleanups) cleanup() // delete require.cache['aws-sdk'] // hopefully this isn't needed // format const account = (_.get(awsConfig, 'credentials.roleArn', '').match(/:\d{12}:/) || [''])[0].replace(/:/gi, '') const region = awsConfig.region if (!account || !region) { throw new Error(`AWS profile ${profile} is missing role_arn or region information`) } return { profile, account, region } } function overrideEnv (key: string, value: string): Function { const before = process.env[key] process.env[key] = value return (): void => { if (before === 'undefined') delete process.env[key] else process.env[key] = before } } interface Environments { [key: string]: EnvData } export function loadEnvironment (name: string): EnvData { const environments: Environments = config.get('environments') if (!environments) throw new Error('Missing config.environments') for (const key in environments) { const value = environments[key] environments[pascalCase(key)] = value if (key !== pascalCase(key)) { delete environments[key] } } const envData: EnvData = environments[pascalCase(name)] if (!envData) { throw new Error(`Cannot find config for environment ${name || 'undefined'}`) } return { ...envData, name } }