diff --git a/API.md b/API.md index 9e6ec47..d1061c1 100644 --- a/API.md +++ b/API.md @@ -1147,47 +1147,47 @@ public readonly repositoryVersion: string; ## Enums -### TagsKey +### TagsKey #### Members | **Name** | **Description** | | --- | --- | -| ENVIRONMENT | *No description.* | -| TIMESTAMP_DEPLOY_CDK | *No description.* | -| BUSINESS_UNIT | *No description.* | -| DOMAIN | *No description.* | -| REPOSITORY_NAME | *No description.* | -| REPOSITORY_VERSION | *No description.* | +| ENVIRONMENT | *No description.* | +| TIMESTAMP_DEPLOY_CDK | *No description.* | +| BUSINESS_UNIT | *No description.* | +| DOMAIN | *No description.* | +| REPOSITORY_NAME | *No description.* | +| REPOSITORY_VERSION | *No description.* | --- -##### `ENVIRONMENT` +##### `ENVIRONMENT` --- -##### `TIMESTAMP_DEPLOY_CDK` +##### `TIMESTAMP_DEPLOY_CDK` --- -##### `BUSINESS_UNIT` +##### `BUSINESS_UNIT` --- -##### `DOMAIN` +##### `DOMAIN` --- -##### `REPOSITORY_NAME` +##### `REPOSITORY_NAME` --- -##### `REPOSITORY_VERSION` +##### `REPOSITORY_VERSION` --- diff --git a/src/common/env.ts b/src/common/env.ts index a75194e..0e9276a 100644 --- a/src/common/env.ts +++ b/src/common/env.ts @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/no-shadow */ +export const CDK_REGION = process.env.CDK_DEFAULT_REGION ?? ''; +export const CDK_ACCOUNT_ID = process.env.CDK_DEFAULT_ACCOUNT ?? ''; export const ENVIRONMENT = process.env.ENVIRONMENT ?? ''; export const BUSINESS_UNIT = process.env.BUSINESS_UNIT ?? ''; export const DOMAIN = process.env.DOMAIN ?? ''; @@ -6,13 +8,4 @@ export const REPOSITORY_NAME = process.env.REPOSITORY_NAME ?? ''; export const REPOSITORY_VERSION = process.env.REPOSITORY_VERSION ?? ''; let timestamp = new Date(); -export const TIMESTAMP_DEPLOY_CDK = `${timestamp.getFullYear().toString()}/${timestamp.getMonth().toString()}/${timestamp.getDay().toString()} H:${timestamp.getHours().toString()}`; - -export enum TagsKey { - ENVIRONMENT='Environment', - TIMESTAMP_DEPLOY_CDK='TimestampDeployCDK', - BUSINESS_UNIT='BusinessUnit', // Indicates which business unit competes for the service released on aws - DOMAIN='Domain', // Indicates the domain in which the service operates - REPOSITORY_NAME='RepositoryName', // Indicates in which repository the released code is contained - REPOSITORY_VERSION='RepositoryVersion', // Indicates which version of the code was released (can be a tag or a commit hash) -} \ No newline at end of file +export const TIMESTAMP_DEPLOY_CDK = `${timestamp.getFullYear().toString()}/${timestamp.getMonth().toString()}/${timestamp.getDay().toString()} H:${timestamp.getHours().toString()}`; \ No newline at end of file diff --git a/src/common/utils.ts b/src/common/utils.ts index 6ccbbfa..1c4910f 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -8,27 +8,36 @@ export interface BaseTagProps { readonly repositoryVersion?: string; } +export enum TagsKey { + ENVIRONMENT='Environment', + TIMESTAMP_DEPLOY_CDK='TimestampDeployCDK', + BUSINESS_UNIT='BusinessUnit', // Indicates which business unit competes for the service released on aws + DOMAIN='Domain', // Indicates the domain in which the service operates + REPOSITORY_NAME='RepositoryName', // Indicates in which repository the released code is contained + REPOSITORY_VERSION='RepositoryVersion', // Indicates which version of the code was released (can be a tag or a commit hash) +} + export function addBaseTags(module: any, props?: BaseTagProps) { - Tags.of(module).add(env.TagsKey.ENVIRONMENT, env.ENVIRONMENT); - Tags.of(module).add(env.TagsKey.TIMESTAMP_DEPLOY_CDK, env.TIMESTAMP_DEPLOY_CDK); + Tags.of(module).add(TagsKey.ENVIRONMENT, env.ENVIRONMENT); + Tags.of(module).add(TagsKey.TIMESTAMP_DEPLOY_CDK, env.TIMESTAMP_DEPLOY_CDK); let businessUnit = props?.businessUnit ?? env.BUSINESS_UNIT; if (businessUnit) { - Tags.of(module).add(env.TagsKey.BUSINESS_UNIT, businessUnit); + Tags.of(module).add(TagsKey.BUSINESS_UNIT, businessUnit); } let domain = props?.domain ?? env.DOMAIN; if (domain) { - Tags.of(module).add(env.TagsKey.DOMAIN, domain); + Tags.of(module).add(TagsKey.DOMAIN, domain); } let repositoryName = props?.repositoryName ?? env.REPOSITORY_NAME; if (repositoryName) { - Tags.of(module).add(env.TagsKey.REPOSITORY_NAME, repositoryName); + Tags.of(module).add(TagsKey.REPOSITORY_NAME, repositoryName); } let repositoryVersion = props?.repositoryVersion ?? env.REPOSITORY_VERSION; if (repositoryVersion) { - Tags.of(module).add(env.TagsKey.REPOSITORY_VERSION, repositoryVersion); + Tags.of(module).add(TagsKey.REPOSITORY_VERSION, repositoryVersion); } } diff --git a/src/constructs/aws-lambda/index.ts b/src/constructs/aws-lambda/index.ts new file mode 100644 index 0000000..b8bcdf4 --- /dev/null +++ b/src/constructs/aws-lambda/index.ts @@ -0,0 +1,109 @@ +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import { Construct } from 'constructs'; +import { CDK_ACCOUNT_ID, CDK_REGION } from '../../common/env'; +import * as env from '../../common/env'; +import { addBaseTags } from '../../common/utils'; + +export const NEW_RELIC_LAYERS_ACCOUNT_ID = '451483290750'; // AWS account id of NewRelic where exposed layers https://layers.newrelic-external.com/ + +export interface FunctionProps extends lambda.FunctionProps { + readonly stage: string; +} + +export interface FunctionNewRelicProps extends FunctionProps { + readonly newRelicLayerName: string; + readonly newRelicLayerVersion: number; + readonly newRelicAccountId: string; + readonly newRelicwithExtensionSendLogs?: boolean; +} + +function getConstructId(id: string, stage: string) { + return id + '-construct-' + stage; +} + +abstract class BaseFunction extends Construct { + public readonly stage: string; + public readonly function: lambda.Function; + + constructor(scope: Construct, id: string, props: FunctionProps) { + super(scope, getConstructId(id, props.stage)); + this.stage = props.stage; + this.function = this.createFunction(scope, id, props); + + this.addEnvironment({ + ENVIRONMENT: this.stage, + TIMESTAMP_DEPLOY_CDK: env.TIMESTAMP_DEPLOY_CDK, + BUSINESS_UNIT: env.BUSINESS_UNIT, + DOMAIN: env.DOMAIN, + REPOSITORY_NAME: env.REPOSITORY_NAME, + REPOSITORY_VERSION: env.REPOSITORY_VERSION, + }); + + addBaseTags(this.function); + } + + abstract createFunction(scope: Construct, id: string, props: FunctionProps): lambda.Function; + + addEnvironment(props: { [key: string]: string }) { + let keys = Object.keys(props); + for (let index = 0; index < keys.length; index++) { + let key = keys[index]; + this.function.addEnvironment(key.toUpperCase(), props[key]); + } + } +} +export class Function extends BaseFunction { + constructor(scope: Construct, id: string, props: FunctionProps) { + super(scope, id, props); + } + + createFunction(scope: Construct, id: string, props: FunctionNewRelicProps) { + return new lambda.Function(scope, id, props); + } +} + +export class FunctionNewRelic extends BaseFunction { + constructor(scope: Construct, id: string, props: FunctionNewRelicProps) { + super(scope, id, props); + } + + createFunction(scope: Construct, id: string, props: FunctionNewRelicProps) { + let handler = 'newrelic_lambda_wrapper.handler'; + let app_handler = props.handler; + + let lambdaFunction = new lambda.Function(scope, id, { ...props, handler }); + + lambdaFunction.addToRolePolicy( + new iam.PolicyStatement({ + actions: ['secretsmanager:GetSecretValue'], + resources: [`arn:aws:secretsmanager:eu-west-1:${CDK_ACCOUNT_ID}:secret:NEW_RELIC_LICENSE_KEY-??????`], + }), + ); + + lambdaFunction.addEnvironment('NEW_RELIC_ACCOUNT_ID', props.newRelicAccountId); + lambdaFunction.addEnvironment('NEW_RELIC_LAMBDA_HANDLER', app_handler); + lambdaFunction.addEnvironment('NEW_RELIC_LAMBDA_EXTENSION_ENABLED', 'true'); + if (props.newRelicwithExtensionSendLogs) { + lambdaFunction.addEnvironment('NEW_RELIC_EXTENSION_SEND_FUNCTION_LOGS', 'true'); + } + + lambdaFunction.addLayers(this.getNewRelicLayer( + scope, + lambdaFunction.functionName, + props.newRelicLayerName, + props.newRelicLayerVersion, + CDK_REGION, + )); + + return lambdaFunction; + } + + getNewRelicLayer(scope: Construct, functionName:string, layerName: string, layerVersion: number, region: string) { + return lambda.LayerVersion.fromLayerVersionArn( + scope, + `new-relic-layer-${functionName}`, + `arn:aws:lambda:${region}:${NEW_RELIC_LAYERS_ACCOUNT_ID}:layer:${layerName}:${layerVersion}`, + ); + } +} \ No newline at end of file diff --git a/src/constructs/index.ts b/src/constructs/index.ts new file mode 100644 index 0000000..0ea9679 --- /dev/null +++ b/src/constructs/index.ts @@ -0,0 +1 @@ +export * as aws_lambda from './aws-lambda'; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 67bbba5..714d08d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ export * as stacks from './stacks'; +export * as constructs from './constructs'; export * as env from './common/env'; export * as utils from './common/utils';