UNPKG

serverless-plugin-lambda-insights

Version:

A Serverless Framework Plugin allowing to enable Lambda Insights for entire Serverless stack or individual functions

219 lines (198 loc) 7.34 kB
'use strict'; // Lambda Insight Layer Versions // see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-extension-versions.html const layerVersions = require('./layerVersions.json'); const layerVersionsArm64 = require('./layerVersionsArm64.json'); const lambdaInsightsManagedPolicy = 'arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy'; /** * Serverless Lambda Insights Plugin - serverless-plugin-lambda-insights * @class AddLambdaInsights */ class AddLambdaInsights { /** * AddLambdaInsights constructor * This class gets instantiated with a serverless object and a bunch of options. * @param {object} serverless The serverless instance which enables access to global service config during */ constructor(serverless) { this.serverless = serverless; this.service = this.serverless.service; this.provider = this.serverless.getProvider('aws'); this.hooks = { 'before:package:setupProviderConfiguration': this.addLambdaInsights.bind(this), }; if (this.checkValidationSupport(serverless)) { serverless.configSchemaHandler.defineFunctionProperties('aws', { properties: { lambdaInsights: {type: 'boolean'}, }, }); serverless.configSchemaHandler.defineCustomProperties({ properties: { lambdaInsights: { type: 'object', properties: { defaultLambdaInsights: {type: 'boolean'}, attachPolicy: {type: 'boolean'}, lambdaInsightsVersion: {type: 'number'}, } }, }, }); } } /** * Validates serverless object has required validation fields * @param {any} serverless * @return {boolean} Whether installed serverless fw supports validation */ checkValidationSupport(serverless) { return serverless.configSchemaHandler && serverless.configSchemaHandler.defineFunctionProperties && typeof serverless.configSchemaHandler['defineFunctionProperties'] == 'function' && serverless.configSchemaHandler.defineCustomProperties && typeof serverless.configSchemaHandler['defineCustomProperties'] == 'function'; } /** * Check if Lambda Insights parameter is of type Boolean * @param {any} value Value to check * @return {boolean} return input value if boolean */ checkLambdaInsightsType(value) { if (typeof value === 'boolean') { return value; } else { throw new Error( 'LambdaInsights and DefaultLambdaInsights values must be set to either true or false.', ); } } /** * Check if Lambda Insights Layer Version is valid * @param {any} value Value to check * @return {boolean} return input value if available */ checkLambdaInsightsVersion(value) { if (typeof value === 'number') { return value; } else { throw new Error('lambdaInsightsVersion version must be a number.'); } } /** * Generates a valid Lambda Insights Layer ARN for your Region * @param {number} version Value to check * @return {string} Lambda Insights Layer ARN */ async generateLayerARN(version, architecture) { const region = this.provider.getRegion(); const isArm64 = architecture ? architecture === 'arm64' : this.service.provider.architecture === 'arm64'; if (version) { try { let layerVersionInfo; if (isArm64) { layerVersionInfo = await this.provider.request('Lambda', 'getLayerVersionByArn', { Arn: `arn:aws:lambda:${region}:580247275435:layer:LambdaInsightsExtension-Arm64:${version}`, }); } else { layerVersionInfo = await this.provider.request('Lambda', 'getLayerVersionByArn', { Arn: `arn:aws:lambda:${region}:580247275435:layer:LambdaInsightsExtension:${version}`, }); } return layerVersionInfo.LayerVersionArn; } catch (err) { if (err.code==='AccessDeniedException') { throw new Error( `LambdaInsights layer version '${version}' ` + `does not exist within your region '${region}'.`); } else { throw err; } } } let arn; if (isArm64) { arn = layerVersionsArm64[region]; } else { arn = layerVersions[region]; } if (!arn) { throw new Error( `Unknown latest version for region '${region}'. ` + `Check the Lambda Insights documentation to get the list of currently supported versions.`); } return arn; }; /** * Attach Lambda Layer conditionally to each function * @param {boolean} globalLambdaInsights global settings * @param {number} layerVersion global layerVersion settings * @param {boolean} attachPolicy global attachPolicy settings */ async addLambdaInsightsToFunctions(globalLambdaInsights, layerVersion, attachPolicy) { if (typeof this.service.functions !== 'object') { return; } try { let policyToggle = false; const functions = Object.keys(this.service.functions); for (const functionName of functions) { const fn = this.service.functions[functionName]; const layerARN = await this.generateLayerARN(layerVersion, fn.architecture); const localLambdaInsights = fn.hasOwnProperty('lambdaInsights') ? this.checkLambdaInsightsType(fn.lambdaInsights) : null; if ( localLambdaInsights === false || (localLambdaInsights === null && globalLambdaInsights === null) ) { continue; } const fnLambdaInsights = localLambdaInsights || globalLambdaInsights; if (fnLambdaInsights) { // attach Lambda Layer fn.layers = fn.layers || []; fn.layers.push(layerARN); policyToggle = true; } }; if (attachPolicy && policyToggle) { // attach CloudWatchLambdaInsightsExecutionRolePolicy this.service.provider.iamManagedPolicies = this.service.provider.iamManagedPolicies || []; this.service.provider.iamManagedPolicies.push(lambdaInsightsManagedPolicy); } return; } catch (err) { throw err; } } /** * Hook function to get global config value and executes addLambdaInsightsToFunctions * @return {Promise} Lambda Insights Layer ARN */ addLambdaInsights() { const customLambdaInsights = this.service.custom && this.service.custom.lambdaInsights; const globalLambdaInsights = customLambdaInsights && customLambdaInsights.defaultLambdaInsights ? this.checkLambdaInsightsType( customLambdaInsights.defaultLambdaInsights, ) : null; const attachPolicy = customLambdaInsights && customLambdaInsights.hasOwnProperty('attachPolicy') ? this.checkLambdaInsightsType( customLambdaInsights.attachPolicy, ) : true; const layerVersion = customLambdaInsights && customLambdaInsights.lambdaInsightsVersion ? this.checkLambdaInsightsVersion( customLambdaInsights.lambdaInsightsVersion, ) : null; return this.addLambdaInsightsToFunctions(globalLambdaInsights, layerVersion, attachPolicy); } } module.exports = AddLambdaInsights;