@sylvesterllc/aws-constructs 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/.github/workflows/publish.yml +36 -0
  2. package/dist/config/AppConfig.d.ts +24 -0
  3. package/dist/config/AppConfig.js +62 -0
  4. package/dist/config/Constants.d.ts +26 -0
  5. package/dist/config/Constants.js +30 -0
  6. package/dist/config/Environments.d.ts +2 -0
  7. package/dist/config/Environments.js +3 -0
  8. package/dist/config/MicroserviceAppConfig.d.ts +5 -0
  9. package/dist/config/MicroserviceAppConfig.js +11 -0
  10. package/dist/config/bishopConfig.d.ts +2 -0
  11. package/dist/config/bishopConfig.js +81 -0
  12. package/dist/config/customConfigs/ApiAppConfig.d.ts +5 -0
  13. package/dist/config/customConfigs/ApiAppConfig.js +4 -0
  14. package/dist/config/customConfigs/GlobalAppConfig.d.ts +8 -0
  15. package/dist/config/customConfigs/GlobalAppConfig.js +3 -0
  16. package/dist/config/customConfigs/IAppConfig.d.ts +10 -0
  17. package/dist/config/customConfigs/IAppConfig.js +3 -0
  18. package/dist/config/customConfigs/ResourceAppConfig.d.ts +8 -0
  19. package/dist/config/customConfigs/ResourceAppConfig.js +3 -0
  20. package/dist/config/microServiceConfig.d.ts +2 -0
  21. package/dist/config/microServiceConfig.js +82 -0
  22. package/dist/config/types/TsgCdkConfigType.d.ts +3 -0
  23. package/dist/config/types/TsgCdkConfigType.js +3 -0
  24. package/dist/config/types/TsgCognitoConfig.d.ts +5 -0
  25. package/dist/config/types/TsgCognitoConfig.js +3 -0
  26. package/dist/config/types/TsgDnsConfig.d.ts +9 -0
  27. package/dist/config/types/TsgDnsConfig.js +3 -0
  28. package/dist/config/types/TsgDynamoDbProp.d.ts +6 -0
  29. package/dist/config/types/TsgDynamoDbProp.js +3 -0
  30. package/dist/config/types/TsgDynamoIndex.d.ts +13 -0
  31. package/dist/config/types/TsgDynamoIndex.js +3 -0
  32. package/dist/config/types/TsgDynamoProp.d.ts +15 -0
  33. package/dist/config/types/TsgDynamoProp.js +3 -0
  34. package/dist/config/types/TsgDynamoTable.d.ts +4 -0
  35. package/dist/config/types/TsgDynamoTable.js +3 -0
  36. package/dist/config/types/TsgDynamoTableRef.d.ts +4 -0
  37. package/dist/config/types/TsgDynamoTableRef.js +3 -0
  38. package/dist/config/types/TsgLambda.d.ts +4 -0
  39. package/dist/config/types/TsgLambda.js +3 -0
  40. package/dist/config/types/TsgLambdaLayerProp.d.ts +5 -0
  41. package/dist/config/types/TsgLambdaLayerProp.js +3 -0
  42. package/dist/config/types/TsgLambdaMap.d.ts +3 -0
  43. package/dist/config/types/TsgLambdaMap.js +3 -0
  44. package/dist/config/types/TsgLambdaName.d.ts +1 -0
  45. package/dist/config/types/TsgLambdaName.js +3 -0
  46. package/dist/config/types/TsgLambdaNode.d.ts +3 -0
  47. package/dist/config/types/TsgLambdaNode.js +3 -0
  48. package/dist/config/types/TsgLambdaProp.d.ts +16 -0
  49. package/dist/config/types/TsgLambdaProp.js +3 -0
  50. package/dist/config/types/TsgLambdaProps.d.ts +16 -0
  51. package/dist/config/types/TsgLambdaProps.js +3 -0
  52. package/dist/config/types/TsgLambdaRoutable.d.ts +6 -0
  53. package/dist/config/types/TsgLambdaRoutable.js +3 -0
  54. package/dist/config/types/index.d.ts +8 -0
  55. package/dist/config/types/index.js +25 -0
  56. package/dist/constructs/MicroService.d.ts +12 -0
  57. package/dist/constructs/MicroService.js +47 -0
  58. package/dist/constructs/index.d.ts +1 -0
  59. package/dist/constructs/index.js +6 -0
  60. package/dist/index.d.ts +4 -0
  61. package/dist/index.js +8 -0
  62. package/dist/interfaces/CreateLambdaFunctionInput.d.ts +10 -0
  63. package/dist/interfaces/CreateLambdaFunctionInput.js +3 -0
  64. package/dist/interfaces/MicroserviceProps.d.ts +10 -0
  65. package/dist/interfaces/MicroserviceProps.js +3 -0
  66. package/dist/resources/base/baseResource.d.ts +10 -0
  67. package/dist/resources/base/baseResource.js +11 -0
  68. package/dist/resources/certificate/createCertificate.d.ts +9 -0
  69. package/dist/resources/certificate/createCertificate.js +29 -0
  70. package/dist/resources/cognito/createCognito.d.ts +7 -0
  71. package/dist/resources/cognito/createCognito.js +35 -0
  72. package/dist/resources/cognito/createCognitoProps.d.ts +2 -0
  73. package/dist/resources/cognito/createCognitoProps.js +47 -0
  74. package/dist/resources/dynamodb/CreateDynamo.d.ts +15 -0
  75. package/dist/resources/dynamodb/CreateDynamo.js +87 -0
  76. package/dist/resources/gateway/createApi.d.ts +19 -0
  77. package/dist/resources/gateway/createApi.js +104 -0
  78. package/dist/resources/gateway/createMicroServiceBundle.d.ts +25 -0
  79. package/dist/resources/gateway/createMicroServiceBundle.js +126 -0
  80. package/dist/resources/helpers/createAuthorizer.d.ts +15 -0
  81. package/dist/resources/helpers/createAuthorizer.js +80 -0
  82. package/dist/resources/helpers/createCommonLayer.d.ts +3 -0
  83. package/dist/resources/helpers/createCommonLayer.js +15 -0
  84. package/dist/resources/helpers/createRoutes.d.ts +8 -0
  85. package/dist/resources/helpers/createRoutes.js +30 -0
  86. package/dist/resources/lambda/createLambda.d.ts +20 -0
  87. package/dist/resources/lambda/createLambda.js +135 -0
  88. package/dist/resources/lambda-layer/createLambdaLayer.d.ts +5 -0
  89. package/dist/resources/lambda-layer/createLambdaLayer.js +31 -0
  90. package/dist/resources/layers/common/src/nodejs/api-response/index.d.ts +1 -0
  91. package/dist/resources/layers/common/src/nodejs/api-response/index.js +18 -0
  92. package/dist/resources/layers/common/src/nodejs/api-response/responses.d.ts +24 -0
  93. package/dist/resources/layers/common/src/nodejs/api-response/responses.js +43 -0
  94. package/dist/resources/layers/common/src/nodejs/index.d.ts +2 -0
  95. package/dist/resources/layers/common/src/nodejs/index.js +19 -0
  96. package/dist/resources/layers/common/src/nodejs/logger/IContext.d.ts +5 -0
  97. package/dist/resources/layers/common/src/nodejs/logger/IContext.js +3 -0
  98. package/dist/resources/layers/common/src/nodejs/logger/index.d.ts +2 -0
  99. package/dist/resources/layers/common/src/nodejs/logger/index.js +19 -0
  100. package/dist/resources/layers/common/src/nodejs/logger/logger.d.ts +2 -0
  101. package/dist/resources/layers/common/src/nodejs/logger/logger.js +12 -0
  102. package/dist/resources/resources/iam/policyDocuments/cognitoPolicy.d.ts +4 -0
  103. package/dist/resources/resources/iam/policyDocuments/cognitoPolicy.js +52 -0
  104. package/dist/resources/resources/iam/roles/createRole.d.ts +4 -0
  105. package/dist/resources/resources/iam/roles/createRole.js +22 -0
  106. package/dist/resources/route53/CreateZone.d.ts +0 -0
  107. package/dist/resources/route53/CreateZone.js +47 -0
  108. package/dist/resources/route53/create-zones.d.ts +0 -0
  109. package/dist/resources/route53/create-zones.js +30 -0
  110. package/dist/resources/securityManager/index.d.ts +4 -0
  111. package/dist/resources/securityManager/index.js +18 -0
  112. package/docs/lambda-config.md +1 -0
  113. package/package.json +48 -0
  114. package/readme.md +147 -0
  115. package/src/config/AppConfig.ts +93 -0
  116. package/src/config/Constants.ts +27 -0
  117. package/src/config/Environments.ts +2 -0
  118. package/src/config/MicroserviceAppConfig.ts +9 -0
  119. package/src/config/bishopConfig.ts +83 -0
  120. package/src/config/customConfigs/ApiAppConfig.ts +6 -0
  121. package/src/config/customConfigs/GlobalAppConfig.ts +11 -0
  122. package/src/config/customConfigs/IAppConfig.ts +13 -0
  123. package/src/config/customConfigs/ResourceAppConfig.ts +12 -0
  124. package/src/config/microServiceConfig.ts +85 -0
  125. package/src/config/types/TsgCdkConfigType.ts +3 -0
  126. package/src/config/types/TsgCognitoConfig.ts +6 -0
  127. package/src/config/types/TsgDnsConfig.ts +9 -0
  128. package/src/config/types/TsgDynamoDbProp.ts +7 -0
  129. package/src/config/types/TsgDynamoIndex.ts +16 -0
  130. package/src/config/types/TsgDynamoProp.ts +17 -0
  131. package/src/config/types/TsgDynamoTable.ts +5 -0
  132. package/src/config/types/TsgDynamoTableRef.ts +4 -0
  133. package/src/config/types/TsgLambda.ts +6 -0
  134. package/src/config/types/TsgLambdaLayerProp.ts +5 -0
  135. package/src/config/types/TsgLambdaMap.ts +4 -0
  136. package/src/config/types/TsgLambdaName.ts +4 -0
  137. package/src/config/types/TsgLambdaNode.ts +4 -0
  138. package/src/config/types/TsgLambdaProp.ts +16 -0
  139. package/src/config/types/TsgLambdaProps.ts +19 -0
  140. package/src/config/types/TsgLambdaRoutable.ts +6 -0
  141. package/src/config/types/index.ts +9 -0
  142. package/src/constructs/MicroService.ts +68 -0
  143. package/src/constructs/index.ts +1 -0
  144. package/src/index.ts +4 -0
  145. package/src/interfaces/CreateLambdaFunctionInput.ts +11 -0
  146. package/src/interfaces/MicroserviceProps.ts +11 -0
  147. package/src/resources/.gitkeep +0 -0
  148. package/src/resources/base/baseResource.ts +15 -0
  149. package/src/resources/certificate/createCertificate.ts +40 -0
  150. package/src/resources/cicd/.gitkeep +0 -0
  151. package/src/resources/cognito/.gitkeep +0 -0
  152. package/src/resources/cognito/createCognito.ts +47 -0
  153. package/src/resources/cognito/createCognitoProps.ts +46 -0
  154. package/src/resources/dynamodb/CreateDynamo.ts +111 -0
  155. package/src/resources/gateway/createApi.ts +138 -0
  156. package/src/resources/gateway/createMicroServiceBundle.ts +183 -0
  157. package/src/resources/helpers/createAuthorizer.ts +106 -0
  158. package/src/resources/helpers/createCommonLayer.ts +18 -0
  159. package/src/resources/helpers/createRoutes.ts +43 -0
  160. package/src/resources/lambda/createLambda.ts +184 -0
  161. package/src/resources/lambda-layer/createLambdaLayer.ts +40 -0
  162. package/src/resources/layers/common/package.json +22 -0
  163. package/src/resources/layers/common/src/nodejs/api-response/index.ts +1 -0
  164. package/src/resources/layers/common/src/nodejs/api-response/responses.ts +41 -0
  165. package/src/resources/layers/common/src/nodejs/index.ts +3 -0
  166. package/src/resources/layers/common/src/nodejs/logger/IContext.ts +7 -0
  167. package/src/resources/layers/common/src/nodejs/logger/index.ts +2 -0
  168. package/src/resources/layers/common/src/nodejs/logger/logger.ts +11 -0
  169. package/src/resources/layers/common/tsconfig.json +7 -0
  170. package/src/resources/resources/iam/policyDocuments/cognitoPolicy.ts +55 -0
  171. package/src/resources/resources/iam/roles/createRole.ts +30 -0
  172. package/src/resources/route53/CreateZone.ts +62 -0
  173. package/src/resources/route53/create-zones.ts +41 -0
  174. package/src/resources/securityManager/index.ts +24 -0
  175. package/tsconfig.json +40 -0
@@ -0,0 +1,183 @@
1
+ import { IRestApi, TokenAuthorizer } from "aws-cdk-lib/aws-apigateway";
2
+ import { ITable, Table } from "aws-cdk-lib/aws-dynamodb";
3
+ import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
4
+ import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
5
+ import { Construct } from "constructs";
6
+ import { TsgDynamoTableRef, TsgLambdaProp } from "../../config/types";
7
+ import { TsgLambdaProps } from "../../config/types/TsgLambdaProps";
8
+ import { MicroserviceProps } from "../../interfaces/MicroserviceProps";
9
+ import { CreateAuthorizer } from "../helpers/createAuthorizer";
10
+ import { Routes } from "../helpers/createRoutes";
11
+ import { CreateLambda } from "../lambda/createLambda";
12
+ import { Duration, Stack } from "aws-cdk-lib";
13
+ import { CreateDynamoDb } from "../dynamodb/CreateDynamo";
14
+ import { ISecret } from "aws-cdk-lib/aws-secretsmanager";
15
+ import { LayerVersion } from "aws-cdk-lib/aws-lambda";
16
+ import { AppConfig } from "../../config/AppConfig";
17
+ import { MetricOptions } from "aws-cdk-lib/aws-cloudwatch";
18
+
19
+ export class CreateMicroServiceBundle {
20
+
21
+ protected readonly requireDynamoTableRefs: boolean;
22
+ protected readonly requireAuthorizer: boolean;
23
+
24
+ constructor(scope: Construct,
25
+ private readonly gatewayApi: IRestApi,
26
+ private readonly props: MicroserviceProps,
27
+ private readonly appConfig: AppConfig,
28
+ private readonly tables?: Table[],
29
+ private readonly secretMgr?: ISecret,
30
+ private readonly layers?: LayerVersion[],
31
+ ) {
32
+
33
+ this.requireDynamoTableRefs = (props.RESOURCES.DYNAMO?.TABLE_REFS?.length ?? 0 > 0) ? true : false;
34
+ this.requireAuthorizer = (props.RESOURCES.AUTHORIZER) ? true : false;
35
+ this.onInit(scope);
36
+ }
37
+
38
+ private onInit(scope: Construct) {
39
+
40
+ //console.log("ENTER CreateMicroServiceBundle.onInit");
41
+ let authorizer: TokenAuthorizer|undefined = undefined;
42
+
43
+ // Create Authorizer
44
+ if (this.requireAuthorizer) {
45
+ authorizer = new CreateAuthorizer(scope, this.appConfig, this.props.RESOURCES.AUTHORIZER!).JwtAuthorizer;
46
+ }
47
+
48
+ // Create Lambdas
49
+ const lambdaProp: TsgLambdaProps = {
50
+ scope,
51
+ prop: this.props,
52
+ layers: this.layers,
53
+ appConfig: this.appConfig
54
+ };
55
+
56
+ const lambdas = new CreateLambda(lambdaProp, this.appConfig);
57
+
58
+ if (this.tables) {
59
+ this.AssignAccessToTables(this.tables, lambdas.Lambdas);
60
+ }
61
+
62
+ // Allow access to existing tables
63
+ if (this.requireDynamoTableRefs) {
64
+ this.AssignAccessToTableRefs(scope, this.props.RESOURCES.DYNAMO?.TABLE_REFS, lambdas.Lambdas);
65
+ }
66
+
67
+ if (this.secretMgr) {
68
+ this.AssignAccessToSecretManager(this.secretMgr, lambdas.Lambdas);
69
+ }
70
+
71
+ lambdas.Lambdas.map((lambda) => {
72
+ lambda.metricErrors({
73
+ label: `${lambda.functionName}-errors`,
74
+ period: Duration.minutes(3)
75
+
76
+ })
77
+ });
78
+
79
+ this.AddRoutes(this.props, this.gatewayApi, lambdas.Lambdas, authorizer);
80
+ }
81
+
82
+ private AssignAccessToTables(tables: Table[], lambdas: NodejsFunction[]) {
83
+
84
+ if (tables) {
85
+ tables.forEach((table: ITable) => {
86
+
87
+ lambdas.forEach((lambda: NodejsFunction) => {
88
+
89
+ // This is a CDK bug: It doesn't provide
90
+ // access to the indexes.
91
+ //table.grantReadWriteData(lambda);
92
+
93
+ // Workaround:
94
+ lambda.addToRolePolicy(
95
+ new PolicyStatement({
96
+ effect: Effect.ALLOW,
97
+ actions: CreateDynamoDb.ReadWriteActions,
98
+ resources: [
99
+ table.tableArn,
100
+ `${table.tableArn}/*`, // This is not recognized by cdk, but table is. why?
101
+ ],
102
+ })
103
+ );
104
+
105
+
106
+
107
+ });
108
+
109
+ });
110
+ }
111
+ }
112
+
113
+ private AssignAccessToTableRefs(scope: Construct, tableRefs: TsgDynamoTableRef[] | undefined, lambdas: NodejsFunction[]) {
114
+
115
+ if (tableRefs) {
116
+ tableRefs.forEach((tableRef: TsgDynamoTableRef) => {
117
+
118
+ if (tableRef.region) {
119
+ this.AssignReadWriteAccessToTableInRegion(scope, tableRef, lambdas);
120
+ }
121
+ else {
122
+ this.AssignReadWriteAccessToTable(scope, tableRef, lambdas);
123
+ }
124
+ });
125
+ }
126
+ }
127
+
128
+ private AssignReadWriteAccessToTableInRegion(scope: Construct, tableRef: TsgDynamoTableRef, lambdas: NodejsFunction[]) {
129
+ lambdas.forEach((lambda: NodejsFunction) => {
130
+
131
+ let tableArn = "arn:aws:dynamodb:" + tableRef.region + ":" + ((scope as Stack).account) + ":table/" + tableRef.tableName;
132
+ let statement = new PolicyStatement({
133
+ effect: Effect.ALLOW,
134
+ resources: [
135
+ tableArn,
136
+ tableArn + "/index/*",
137
+ ],
138
+ actions: CreateDynamoDb.ReadWriteActions,
139
+ });
140
+
141
+ lambda.role?.addToPrincipalPolicy(statement);
142
+
143
+ });
144
+ }
145
+
146
+ private AssignReadWriteAccessToTable(scope: Construct, tableRef: TsgDynamoTableRef, lambdas: NodejsFunction[]) {
147
+ let table: ITable = Table.fromTableName(scope, tableRef.tableName, tableRef.tableName);
148
+
149
+ lambdas.forEach((lambda: NodejsFunction) => {
150
+ table.grantReadWriteData(lambda)
151
+
152
+ });
153
+ }
154
+
155
+ private AddRoutes(props: MicroserviceProps,
156
+ gateway: IRestApi,
157
+ lambdas: NodejsFunction[],
158
+ authorizer?: TokenAuthorizer) {
159
+
160
+ this.appConfig.lambdaConfigs?.forEach((prop: TsgLambdaProp) => {
161
+
162
+ const lambdaId = CreateLambda.getIdForLambda(prop);
163
+ const lambdaNode = lambdas.find(x => x.node.id === lambdaId);
164
+
165
+ if (!lambdaNode) {
166
+ throw new Error("Can't find the Lambda Integration");
167
+ }
168
+
169
+ Routes.createResource(prop, gateway, lambdaNode, authorizer);
170
+
171
+ });
172
+ }
173
+
174
+ private AssignAccessToSecretManager(secret: ISecret, lambdas: NodejsFunction[]) {
175
+
176
+ lambdas.forEach((lambda) => {
177
+ const result = secret.grantRead(lambda);
178
+ console.log('Assigning Access to Secret Manager: ',result);
179
+ });
180
+
181
+ }
182
+
183
+ }
@@ -0,0 +1,106 @@
1
+ import { CfnOutput, Duration } from "aws-cdk-lib";
2
+ import { IdentitySource, TokenAuthorizer } from "aws-cdk-lib/aws-apigateway";
3
+ import { ManagedPolicy, ServicePrincipal } from "aws-cdk-lib/aws-iam";
4
+ import { NodejsFunction, NodejsFunctionProps, SourceMapMode } from "aws-cdk-lib/aws-lambda-nodejs";
5
+ import { Construct } from "constructs";
6
+ import * as path from 'path';
7
+ import { AppConfig } from "../../config/AppConfig";
8
+
9
+ import { TsgLambdaProp } from "../../config/types";
10
+ import { MicroserviceProps } from "../../interfaces/MicroserviceProps";
11
+ import { BaseResource } from "../base/baseResource";
12
+ import { CreateLambda } from "../lambda/createLambda";
13
+
14
+ export class CreateAuthorizer extends BaseResource<TokenAuthorizer> {
15
+
16
+ get JwtAuthorizer() {
17
+ return this.createdResources[0];
18
+ }
19
+
20
+ constructor(scope: Construct, props: AppConfig, protected authProps: TsgLambdaProp) {
21
+
22
+ super(scope, props);
23
+
24
+ this.createdResources = this.createResource(scope)!;
25
+
26
+ if (this.createdResources) {
27
+ this.createOutput<TokenAuthorizer>(scope, this.createdResources);
28
+ }
29
+
30
+ }
31
+
32
+ protected createResource(scope: Construct): TokenAuthorizer[] | null {
33
+ return [this.createLambdaAuthorizer(scope, this.authProps)];
34
+ }
35
+
36
+ private createLambdaAuthorizer(scope: Construct, lambdaConfig: TsgLambdaProp) {
37
+ //console.log("ENTER createLambdaAuthorizer");
38
+
39
+ const authorizerProps = this.createLambdaFunctionProps(lambdaConfig!);
40
+
41
+ const lambdaId = CreateLambda.getIdForLambda(lambdaConfig);
42
+ const lambda = new NodejsFunction(scope, lambdaId, authorizerProps);
43
+
44
+ lambda.grantInvoke(new ServicePrincipal('apigateway.amazonaws.com'));
45
+
46
+ if (lambdaConfig?.managedPolicies && lambdaConfig.managedPolicies.length > 0) {
47
+ this.assignManagedPolicies(lambda, lambdaConfig.managedPolicies);
48
+ }
49
+
50
+ const lambdaAuthorizer = new TokenAuthorizer(scope, `${lambdaConfig.name}-authorizer`, {
51
+ handler: lambda,
52
+ authorizerName: lambdaConfig.name,
53
+ resultsCacheTtl: Duration.seconds(0),
54
+ identitySource: IdentitySource.header('Authorization'),
55
+
56
+ });
57
+
58
+ return lambdaAuthorizer;
59
+ }
60
+
61
+ protected createOutput<T>(scope: Construct, createdAssets: T[]): void {
62
+
63
+ const entity = createdAssets[0];
64
+
65
+ // new CfnOutput(scope, `authorizer`, {
66
+ // value: (entity as TokenAuthorizer).authorizerArn
67
+ // });
68
+
69
+ }
70
+
71
+ private createLambdaFunctionProps(prop: TsgLambdaProp) {
72
+
73
+ const lambdaProp: NodejsFunctionProps = {
74
+ entry: path.join(prop.codePath),
75
+ functionName: prop.name,
76
+ handler: prop.handler,
77
+ runtime: prop.runtime || this.config.GLOBALS.stackRuntime,
78
+ timeout: prop.duration || Duration.minutes(2),
79
+ memorySize: prop.memory || 512,
80
+ environment: {
81
+ "VERBOSE_LOGGING": "true",
82
+ ...prop.environment
83
+ },
84
+ bundling: {
85
+ minify: false,
86
+ target: 'es2020',
87
+ sourceMap: true,
88
+ sourceMapMode: SourceMapMode.INLINE,
89
+ environment: prop.environment || prop.environment,
90
+ },
91
+ }
92
+ return lambdaProp;
93
+ };
94
+
95
+ private assignManagedPolicies(lambda: NodejsFunction, managedPolicyNames: string[]) {
96
+
97
+ managedPolicyNames.forEach((managedPolicyName: string) => {
98
+
99
+ let policy = ManagedPolicy.fromAwsManagedPolicyName(managedPolicyName);
100
+
101
+ lambda.role?.addManagedPolicy(policy);
102
+ });
103
+
104
+ }
105
+
106
+ }
@@ -0,0 +1,18 @@
1
+ import { Construct } from "constructs";
2
+ import { createLambdaLayer } from "../lambda-layer/createLambdaLayer";
3
+ import { TsgLambdaLayerProp } from "../../config/types/TsgLambdaLayerProp";
4
+ import { AppConfig } from "../../config/AppConfig";
5
+
6
+ export const createCommonLayer = (scope: Construct, appProps: AppConfig) => {
7
+
8
+ const prop: TsgLambdaLayerProp = {
9
+ description: 'Common Lambda layer',
10
+ codePath: './node_modules/@davissylvester/bishop-cdk-constructs/dist',
11
+ name: 'bishop-common-layer'
12
+ };
13
+
14
+ const layer = createLambdaLayer(scope, appProps, prop)
15
+
16
+ return layer;
17
+ };
18
+
@@ -0,0 +1,43 @@
1
+ import { IRestApi, LambdaIntegration, Resource, TokenAuthorizer } from "aws-cdk-lib/aws-apigateway";
2
+ import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
3
+ import { TsgLambdaProp } from "../../config/types";
4
+
5
+
6
+ export class Routes {
7
+
8
+ public static Resources: Resource[] = [];
9
+ private static routeMap = new Map();
10
+
11
+ public static createResource(
12
+ prop: TsgLambdaProp,
13
+ api: IRestApi,
14
+ lambdaNode: NodejsFunction,
15
+ authorizer?: TokenAuthorizer) {
16
+
17
+ const routeMap: Map<string, Resource> = new Map();
18
+
19
+ // Only attach lambda to an Api Gateway if a route exist
20
+ if (prop.apiGateway?.route) {
21
+
22
+ // Note: this now uses the bundle version as the first segment in the path.
23
+ let activeRoutePath = `/${(prop.apiGateway.version) ? prop.apiGateway.version : 1 }`;
24
+ let activeResource: Resource = Routes.routeMap.get(activeRoutePath) || api.root.addResource(activeRoutePath);
25
+ Routes.routeMap.set(activeRoutePath, activeResource);
26
+
27
+ // Now we go through our route segments creating the rest of the path.
28
+ const pathSegments = prop.apiGateway?.route.split("/").filter(x => (x));
29
+ for (let i = 0; i < pathSegments.length; i++) {
30
+ activeRoutePath = `${activeRoutePath}/${pathSegments[i]}`;
31
+ let secondaryResource = Routes.routeMap.get(activeRoutePath) || activeResource!.addResource(pathSegments[i]);
32
+ Routes.routeMap.set(activeRoutePath, secondaryResource);
33
+ activeResource = secondaryResource;
34
+ }
35
+
36
+ // Finally, we attach our function to the last resource
37
+ activeResource.addMethod(prop.apiGateway.method || 'GET',
38
+ new LambdaIntegration(lambdaNode, { proxy: true, }),
39
+ prop.apiGateway.secure ? { authorizer } : undefined);
40
+ }
41
+ }
42
+
43
+ }
@@ -0,0 +1,184 @@
1
+ import { CfnOutput, Duration } from "aws-cdk-lib";
2
+ import { TokenAuthorizer } from "aws-cdk-lib/aws-apigateway";
3
+ import { Alarm, ComparisonOperator, IAlarmAction } from "aws-cdk-lib/aws-cloudwatch";
4
+ import { IRole, ManagedPolicy } from "aws-cdk-lib/aws-iam";
5
+ import { LayerVersion } from "aws-cdk-lib/aws-lambda";
6
+ import { NodejsFunction, NodejsFunctionProps, SourceMapMode } from "aws-cdk-lib/aws-lambda-nodejs";
7
+ import { Construct } from "constructs";
8
+ import * as path from 'path';
9
+ import { AppConfig } from "../../config/AppConfig";
10
+ import { TsgLambdaProp } from "../../config/types";
11
+
12
+ import { TsgLambdaProps } from "../../config/types/TsgLambdaProps";
13
+ import { CreateLambdaFunctionInput } from "../../interfaces/CreateLambdaFunctionInput";
14
+ import { BaseResource } from "../base/baseResource";
15
+
16
+
17
+ export class CreateLambda extends BaseResource<NodejsFunction> {
18
+
19
+ public Lambdas: NodejsFunction[] = [];
20
+
21
+
22
+ constructor(private props: TsgLambdaProps, config: AppConfig) {
23
+ super(props.scope, config);
24
+
25
+ const resources = this.createResource(props.scope);
26
+
27
+ this.Lambdas = [...resources];
28
+
29
+ this.createAlarmsForLambdas(this.Lambdas);
30
+
31
+ this.createOutput(props.scope, resources);
32
+ }
33
+
34
+ protected createResource(scope: Construct): NodejsFunction[] {
35
+
36
+ const result = this.createLambdas(this.props);
37
+
38
+ return result;
39
+ }
40
+
41
+ protected createOutput<T>(scope: Construct, createdAssets: T[]): void {
42
+ createdAssets.forEach((x, idx) => {
43
+
44
+ new CfnOutput(scope, `lambda-${idx}`, {
45
+ // @ts-ignore
46
+ value: x.functionName
47
+ });
48
+ });
49
+ }
50
+
51
+ private createLambdas(props: TsgLambdaProps): NodejsFunction[] {
52
+
53
+ const createdLambdas: NodejsFunction[] = this.createLambdaFunctions(this.scope, props.role, props.layers);
54
+
55
+ return createdLambdas;
56
+ }
57
+
58
+ private createLambdaFunctions(scope: Construct, role?: IRole, layers?: LayerVersion[]) {
59
+
60
+ //console.log("ENTER createLambdaFunctions");
61
+ const createdLambdas = this.props.prop.RESOURCES.LAMBDA.map((config:TsgLambdaProp) => {
62
+
63
+ //console.log("ENTER createLambdaFunctions.map for " + config.name);
64
+ let lambdaProps = this.createLambdaProps(config, role, layers);
65
+
66
+ const lambdaId = CreateLambda.getIdForLambda(config);
67
+ let fctn = new NodejsFunction(scope, lambdaId, lambdaProps);
68
+
69
+ // If we have managed policies, we add them.
70
+ if (config.managedPolicies && config.managedPolicies?.length > 0) {
71
+
72
+ this.assignManagedPolicies(fctn, config.managedPolicies);
73
+ }
74
+
75
+ return fctn;
76
+ });
77
+
78
+ return createdLambdas || [];
79
+ }
80
+
81
+ private createLambdaProps(prop: TsgLambdaProp, role?: IRole, layers?: LayerVersion[], props?: TsgLambdaProps) {
82
+
83
+ return this.createLambdaFunctionProps({
84
+ prop,
85
+ role,
86
+ layers,
87
+ props
88
+ });
89
+ }
90
+
91
+ private createLambdaFunctionProps(props: CreateLambdaFunctionInput) {
92
+ const { prop, role, layers } = props;
93
+
94
+ const lambdaProp: NodejsFunctionProps = {
95
+ entry: path.join(prop.codePath),
96
+ functionName: `${this.props.appConfig.AppPrefix}-${prop.name}`,
97
+ handler: prop.handler,
98
+ runtime: prop.runtime || this.config.GLOBALS.stackRuntime,
99
+ timeout: prop.duration || Duration.minutes(2),
100
+ memorySize: prop.memory || 512,
101
+ environment: {
102
+ "VERBOSE_LOGGING": "true",
103
+ ...prop.environment
104
+ },
105
+ bundling: {
106
+ minify: false,
107
+ target: 'es2020',
108
+ sourceMap: true,
109
+ sourceMapMode: SourceMapMode.INLINE,
110
+ environment: prop.environment || prop.environment,
111
+ },
112
+ role,
113
+ layers
114
+
115
+ }
116
+
117
+
118
+ return lambdaProp;
119
+ };
120
+
121
+ private assignManagedPolicies(lambda: NodejsFunction, managedPolicyNames: string[]) {
122
+
123
+ managedPolicyNames.forEach((managedPolicyName: string) => {
124
+
125
+ let policy = ManagedPolicy.fromAwsManagedPolicyName(managedPolicyName);
126
+
127
+ lambda.role?.addManagedPolicy(policy);
128
+ });
129
+
130
+ }
131
+
132
+ private createAlarmsForLambdas(lambdas: NodejsFunction[]) {
133
+
134
+ lambdas.forEach((lambda, idx) => {
135
+
136
+ const errorMetric = lambda.metricErrors({
137
+ period: Duration.minutes(3),
138
+
139
+ });
140
+
141
+ const durationMetric = lambda.metricDuration({
142
+ period: Duration.minutes(3),
143
+ });
144
+
145
+ const invocationMetric = lambda.metricInvocations({
146
+ period: Duration.minutes(3),
147
+ });
148
+
149
+ new Alarm(this.props.scope, `${this.config.AppPrefix}-${idx}-error-alarm`, {
150
+ metric: errorMetric,
151
+ threshold: 5,
152
+ comparisonOperator: ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
153
+ evaluationPeriods: 3,
154
+ alarmDescription: `${this.config.AppPrefix}-${idx} errors over 3 min period`,
155
+ alarmName: `${this.config.AppPrefix}-${idx}-error-alarm`
156
+ });
157
+
158
+ new Alarm(this.props.scope, `${this.config.AppPrefix}-${idx}-duration-alarm`, {
159
+ metric: durationMetric,
160
+ threshold: 1,
161
+ comparisonOperator: ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
162
+ evaluationPeriods: 3,
163
+ alarmDescription: `${this.config.AppPrefix}-${idx} duration errors over 3 min period`,
164
+ alarmName: `${this.config.AppPrefix}-${idx}-duration-alarm`
165
+ });
166
+
167
+ const invocationAlarm = new Alarm(this.props.scope, `${this.config.AppPrefix}-${idx}-invocation-alarm`, {
168
+ metric: errorMetric,
169
+ threshold: 1000,
170
+ comparisonOperator: ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
171
+ evaluationPeriods: 3,
172
+ alarmDescription: `${this.config.AppPrefix}-${idx} errors over 3 min period`,
173
+ alarmName: `${this.config.AppPrefix}-${idx}-invocation-Metric-alarm`
174
+ });
175
+
176
+ // const alarmAction: IAlarmAction = {};
177
+ // invocationAlarm.addAlarmAction(alarmAction);
178
+ });
179
+ }
180
+
181
+ public static getIdForLambda(lambdaProp: TsgLambdaProp) {
182
+ return `${lambdaProp.name}`.toLowerCase();
183
+ }
184
+ }
@@ -0,0 +1,40 @@
1
+ import { Code, LayerVersion, LayerVersionProps, Runtime } from "aws-cdk-lib/aws-lambda";
2
+ import { Construct } from "constructs";
3
+ import { TsgLambdaLayerProp } from "../../config/types/TsgLambdaLayerProp";
4
+ import { MicroserviceProps } from "../../interfaces/MicroserviceProps";
5
+ import * as path from "path";
6
+
7
+ export const createLambdaLayer = (scope: Construct, globalProps: MicroserviceProps, prop: TsgLambdaLayerProp) => {
8
+
9
+ const propResult = createLambdaLayerProps(prop, globalProps);
10
+
11
+ const layer = new LayerVersion(scope, `${globalProps.GLOBALS.name}-common-layer`, propResult);
12
+
13
+ return layer;
14
+
15
+ };
16
+
17
+ const createLambdaLayerProps = (prop: TsgLambdaLayerProp, props: MicroserviceProps) => {
18
+
19
+ const baseProps = baseLayerProps(props, prop.description);
20
+
21
+ const baseLayer: LayerVersionProps = {
22
+ ...baseProps,
23
+ code: Code.fromAsset(path.join(prop.codePath),),
24
+ description: prop.description,
25
+ layerVersionName: `${prop.name}`
26
+ };
27
+ return baseLayer;
28
+ };
29
+
30
+ const baseLayerProps = (prop: MicroserviceProps, desc: string) => {
31
+
32
+ const baseLayerProps: LayerVersionProps = {
33
+ code: Code.fromAsset(path.join(''),),
34
+ compatibleRuntimes: [prop.GLOBALS.stackRuntime],
35
+ license: 'Apache-2.0',
36
+ description: desc,
37
+ };
38
+
39
+ return baseLayerProps;
40
+ };
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@davissylvester/bishop-common",
3
+ "version": "1.0.0",
4
+ "description": "Common Layers for Lambdas",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "jest && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "Davis Sylvester <Davis@sylvesterllc.com>",
11
+ "license": "ISC",
12
+ "dependencies": {
13
+ "@aws-sdk/client-dynamodb": "^3.137.0",
14
+ "@aws-sdk/lib-dynamodb": "^3.145.0",
15
+ "@aws-sdk/util-dynamodb": "^3.137.0",
16
+ "luxon": "^3.0.4",
17
+ "uuidv4": "^6.2.13"
18
+ },
19
+ "devDependencies": {
20
+ "@types/aws-lambda": "^8.10.111"
21
+ }
22
+ }
@@ -0,0 +1 @@
1
+ export * from "./responses";
@@ -0,0 +1,41 @@
1
+ export const badResponse = (errorMessage: string) => {
2
+ return {
3
+ statusCode: 400,
4
+ body: JSON.stringify({
5
+ message: errorMessage
6
+ }),
7
+ headers: {
8
+ "Access-Control-Allow-Origin": "*",
9
+ "Access-Control-Allow-Credentials": true,
10
+ },
11
+ };
12
+
13
+ };
14
+
15
+ export const okResponse = (data: Object) => {
16
+ return {
17
+ statusCode: 200,
18
+ body: JSON.stringify({
19
+ data
20
+ }),
21
+ headers: {
22
+ "Access-Control-Allow-Origin": "*",
23
+ "Access-Control-Allow-Credentials": true,
24
+ },
25
+ };
26
+
27
+ };
28
+
29
+ export const unauthorizedResponse = (data: object) => {
30
+ return {
31
+ statusCode: 401,
32
+ body: JSON.stringify({
33
+ data
34
+ }),
35
+ headers: {
36
+ "Access-Control-Allow-Origin": "*",
37
+ "Access-Control-Allow-Credentials": true,
38
+ },
39
+ };
40
+
41
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./logger/index";
2
+ export * from "./api-response/index";
3
+
@@ -0,0 +1,7 @@
1
+ export interface ILoggerContext {
2
+
3
+ functionName?: string;
4
+ name: string;
5
+ message: string;
6
+
7
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./IContext";
2
+ export * from "./logger";
@@ -0,0 +1,11 @@
1
+ import { ILoggerContext } from "./IContext";
2
+
3
+ export function logger(context: ILoggerContext) {
4
+
5
+ const showLogs = Boolean(process.env.VERBOSE_LOGGING || false);
6
+
7
+ if (showLogs) {
8
+ console.log(`### ${(context.functionName) ? `${context.functionName} :: ` : ''} ${(context.name) ? `${context.name} :: ` : ''} ${(context.message) ? `${context.message} :: ` : ''}`);
9
+ }
10
+ // ### run() ::
11
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist/nodejs/node_modules/@davissylvester/bishop-common",
5
+ "skipLibCheck": true
6
+ }
7
+ }