Skip to content

Commit b2a9b0b

Browse files
authored
Merge pull request #23 from Virtual-Finland-Development/feat/esco-api
Esco API
2 parents a386c9d + 7ec2944 commit b2a9b0b

19 files changed

Lines changed: 979 additions & 628 deletions

infra/Pulumi.dev.yaml

Lines changed: 0 additions & 2 deletions
This file was deleted.

infra/Pulumi.staging.yaml

Lines changed: 0 additions & 2 deletions
This file was deleted.

infra/Pulumi.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
name: codesets
22
description: Codesets infra builder
33
runtime: nodejs
4+
config:
5+
aws:region: us-east-1 # // Lambda@Edge functions must be deployed in us-east-1
6+
escoApi:awsRegion: eu-north-1

infra/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import createLambdaAtEdgeFunction from './resources/LambdaAtEdge';
88
import createS3Bucket, {createS3BucketPermissions, uploadAssetsToBucket} from './resources/S3Bucket';
99
import {getSetup} from './utils/Setup';
1010
import {createStandardLogsBucket} from "./resources/standardLogsBucket";
11+
import { createEscoApiLambdaFunctionUrl } from './resources/LambdaFunctionUrl';
1112

1213
const setup = getSetup();
1314
const originAccessIdentity = createOriginAccessIdentity(setup);
@@ -25,11 +26,17 @@ const cloudFrontDistribution = createCloudFrontDistribution(
2526
uploadAssetsToBucket(s3bucketSetup.bucket);
2627
createCacheInvalidation(setup, cloudFrontDistribution);
2728

29+
// Codesets
2830
export const url = pulumi.interpolate`https://${cloudFrontDistribution.domainName}`;
2931
export const bucketName = s3bucketSetup.bucket.bucket;
30-
export const lambdaId = pulumi.interpolate`${edgeLambdaPackage.lambdaAtEdgeFunction.name}:${edgeLambdaPackage.lambdaAtEdgeFunction.version}`
32+
export const lambdaId = pulumi.interpolate`${edgeLambdaPackage.lambdaAtEdgeFunction.name}:${edgeLambdaPackage.lambdaAtEdgeFunction.version}`;
3133
export const cloudFrontDistributionId = cloudFrontDistribution.id;
3234
export const standardLogsBucketDetails = {
3335
arn: standardLogsBucket.arn,
3436
id: standardLogsBucket.id
3537
}
38+
39+
// Esco API
40+
const escoApi = createEscoApiLambdaFunctionUrl(setup, url);
41+
export const escoApiUrl = escoApi.lambdaFunctionUrl.functionUrl;
42+
export const escoApiLambdaId = escoApi.lambdaFunction.id;

infra/package-lock.json

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

infra/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22
"name": "codesets-infra",
33
"main": "index.ts",
44
"dependencies": {
5-
"@pulumi/aws": "^5.30.0",
6-
"@pulumi/command": "^0.7.1",
7-
"@pulumi/pulumi": "^3.55.0",
5+
"@pulumi/aws": "^5.41.0",
6+
"@pulumi/command": "^0.7.2",
7+
"@pulumi/pulumi": "^3.69.0",
88
"mime": "^3.0.0"
99
},
1010
"scripts": {
1111
"prebuild": "rimraf dist",
12-
"build": "mkdir -p ./dist && cp -r ../dist/* ./dist/ && cp ../package.json ./dist/ && cp ../package-lock.json ./dist/ && npm install --prefix ./dist --omit=dev && rm ./dist/build/*.js"
12+
"build": "mkdir -p ./dist && cp -r ../dist/* ./dist/ && cp ../package.json ./dist/ && cp ../package-lock.json ./dist/ && npm install --prefix ./dist --omit=dev",
13+
"postbuild": "mv ./dist/node_modules ./dist/codesets/ && rm ./dist/codesets/build/*.js"
1314
},
1415
"devDependencies": {
1516
"@types/mime": "^3.0.1",
1617
"rimraf": "^4.1.2"
1718
}
18-
}
19+
}

infra/resources/LambdaAtEdge.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default function createLambdaAtEdgeFunction(
4040

4141
// pass the bucket name to the lambda function dist folder
4242
fs.writeFileSync(
43-
'./dist/build/bucket-info.json',
43+
'./dist/codesets/build/bucket-info.json',
4444
JSON.stringify({
4545
name: s3BucketSetup.name,
4646
})
@@ -49,17 +49,15 @@ export default function createLambdaAtEdgeFunction(
4949

5050
const lambdaAtEdgeFunctionConfig = setup.getResourceConfig('LambdaAtEdge');
5151
const lambdaAtEdgeFunction = new aws.lambda.Function(lambdaAtEdgeFunctionConfig.name, {
52-
code: new pulumi.asset.FileArchive('./dist'),
53-
handler: 'app.handler',
52+
code: new pulumi.asset.FileArchive('./dist/codesets'),
53+
handler: 'codesets.handler',
5454
runtime: 'nodejs18.x',
5555
memorySize: 256,
5656
timeout: 30,
5757
role: lambdaAtEdgeRole.arn,
5858
tags: lambdaAtEdgeFunctionConfig.tags,
5959
publish: true,
6060
});
61-
// { provider: new aws.Provider("us-east-1", { region: "us-east-1"} ) }
62-
// Lambda@Edge functions must be in us-east-1
6361

6462
return {
6563
lambdaAtEdgeFunction,
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import * as aws from '@pulumi/aws';
2+
import * as pulumi from '@pulumi/pulumi';
3+
import { ISetup } from '../utils/Setup';
4+
5+
export function createEscoApiLambdaFunctionUrl(setup: ISetup, codesetsUrl: pulumi.Output<string>) {
6+
const escoApiLambdaFunctionExecRoleConfig = setup.getResourceConfig('EscoApiLambdaFunctionExecRole');
7+
const escoApiLambdaFunctionExecRoleRole = new aws.iam.Role(escoApiLambdaFunctionExecRoleConfig.name, {
8+
assumeRolePolicy: JSON.stringify({
9+
Version: '2012-10-17',
10+
Statement: [
11+
{
12+
Action: 'sts:AssumeRole',
13+
Principal: {
14+
Service: ['lambda.amazonaws.com'],
15+
},
16+
Effect: 'Allow',
17+
},
18+
],
19+
}),
20+
tags: escoApiLambdaFunctionExecRoleConfig.tags,
21+
});
22+
23+
const escoApiLambdaFunctionExecRolePolicy = setup.getResourceConfig('EscoApiLambdaFunctionExecRolePolicy');
24+
new aws.iam.RolePolicy(escoApiLambdaFunctionExecRolePolicy.name, {
25+
role: escoApiLambdaFunctionExecRoleRole.id,
26+
policy: JSON.stringify({
27+
Version: '2012-10-17',
28+
Statement: [
29+
{
30+
Action: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
31+
Resource: 'arn:aws:logs:*:*:*',
32+
Effect: 'Allow',
33+
},
34+
],
35+
}),
36+
});
37+
38+
const escoApiConfig = new pulumi.Config('escoApi');
39+
const escoApiRegionConfig = setup.getResourceConfig('EscoApiRegion');
40+
const escoApiRegion = new aws.Provider(escoApiRegionConfig.name, {
41+
region: escoApiConfig.require('awsRegion') as aws.Region,
42+
});
43+
44+
const escoApiLambdaFunctionConfig = setup.getResourceConfig('EscoApiLambdaFunction');
45+
const escoApiLambdaFunction = new aws.lambda.Function(
46+
escoApiLambdaFunctionConfig.name,
47+
{
48+
role: escoApiLambdaFunctionExecRoleRole.arn,
49+
runtime: 'nodejs18.x',
50+
handler: 'index.handler',
51+
timeout: 30,
52+
memorySize: 256,
53+
code: new pulumi.asset.FileArchive('./dist/escoApi'),
54+
tags: escoApiLambdaFunctionConfig.tags,
55+
environment: {
56+
variables: {
57+
CODESETS_API_ENDPOINT: pulumi.interpolate`${codesetsUrl}`,
58+
},
59+
},
60+
},
61+
{ provider: escoApiRegion }
62+
);
63+
64+
const escoApiLambdaFunctionUrlConfig = setup.getResourceConfig('EscoApiLambdaFunctionUrl');
65+
const escoApiLambdaFunctionUrl = new aws.lambda.FunctionUrl(
66+
escoApiLambdaFunctionUrlConfig.name,
67+
{
68+
functionName: escoApiLambdaFunction.name,
69+
authorizationType: 'NONE',
70+
cors: {
71+
allowCredentials: false,
72+
allowOrigins: ['*'],
73+
allowMethods: ['POST'],
74+
},
75+
},
76+
{ provider: escoApiRegion }
77+
);
78+
79+
// Warmup scheduler for lambda function
80+
if (setup.isProductionLikeEnvironment()) {
81+
setupLambdaWarmerScheduler(setup, escoApiLambdaFunction, escoApiRegion);
82+
}
83+
84+
return {
85+
lambdaFunctionExecRoleRole: escoApiLambdaFunctionExecRoleRole,
86+
lambdaFunction: escoApiLambdaFunction,
87+
lambdaFunctionUrl: escoApiLambdaFunctionUrl,
88+
};
89+
}
90+
91+
function setupLambdaWarmerScheduler(
92+
setup: ISetup,
93+
escoApiLambdaFunction: aws.lambda.Function,
94+
escoApiRegion: aws.Provider
95+
) {
96+
const escoApiWarmupSchedulerEventConfig = setup.getResourceConfig('EscoApiWarmupSchedulerEvent');
97+
const escoApiWarmupSchedulerEvent = new aws.cloudwatch.EventRule(
98+
escoApiWarmupSchedulerEventConfig.name,
99+
{
100+
scheduleExpression: 'rate(5 minutes)',
101+
description: 'Warmup scheduler for Esco API lambda function',
102+
tags: escoApiWarmupSchedulerEventConfig.tags,
103+
},
104+
{ provider: escoApiRegion }
105+
);
106+
107+
const escoApiWarmupSchedulerTargetConfig = setup.getResourceConfig('EscoApiWarmupSchedulerTarget');
108+
new aws.cloudwatch.EventTarget(
109+
escoApiWarmupSchedulerTargetConfig.name,
110+
{
111+
rule: escoApiWarmupSchedulerEvent.name,
112+
arn: escoApiLambdaFunction.arn,
113+
input: JSON.stringify({ source: 'warmup' }),
114+
},
115+
{ provider: escoApiRegion }
116+
);
117+
118+
// Permission for the warmup scheduler to invoke the lambda function
119+
const escoApiWarmupSchedulerPermissionConfig = setup.getResourceConfig('EscoApiWarmupSchedulerPermission');
120+
new aws.lambda.Permission(
121+
escoApiWarmupSchedulerPermissionConfig.name,
122+
{
123+
action: 'lambda:InvokeFunction',
124+
function: escoApiLambdaFunction.name,
125+
principal: 'events.amazonaws.com',
126+
sourceArn: escoApiWarmupSchedulerEvent.arn,
127+
},
128+
{ provider: escoApiRegion }
129+
);
130+
}

infra/utils/Setup.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ const setup = {
1313
},
1414
};
1515
},
16+
isProductionLikeEnvironment() {
17+
return this.stage === 'production' || this.stage === 'staging';
18+
},
1619
};
1720

1821
type ISetup = typeof setup;

0 commit comments

Comments
 (0)