diff --git a/deployment/.gitignore b/deployment/.gitignore index 091f244794..57d113df52 100644 --- a/deployment/.gitignore +++ b/deployment/.gitignore @@ -7,3 +7,5 @@ node_modules # CDK asset staging directory .cdk.staging cdk.out + +package-lock.json \ No newline at end of file diff --git a/deployment/lambdas/cf-url-rewriter/cf-url-rewriter.ts b/deployment/lambdas/cf-url-rewriter/cf-url-rewriter.ts new file mode 100644 index 0000000000..b56d6f49e7 --- /dev/null +++ b/deployment/lambdas/cf-url-rewriter/cf-url-rewriter.ts @@ -0,0 +1,14 @@ +import { CloudFrontRequest, CloudFrontRequestCallback, CloudFrontRequestEvent, Context } from 'aws-lambda'; + +export const handle = (request: CloudFrontRequest) => { + // Incoming URLs from ci.opensearch.org will have a '/ci/123/' prefix, remove the prefix path from requests into S3. + request.uri = request.uri.replace(/^\/ci\/...\//, '\/'); +} + +export async function handler(event: CloudFrontRequestEvent, context: Context, callback: CloudFrontRequestCallback) { + const request = event.Records[0].cf.request; + + handle(request); + + callback(null, request); +} \ No newline at end of file diff --git a/deployment/lambdas/cf-url-rewriter/package-lock.json b/deployment/lambdas/cf-url-rewriter/package-lock.json new file mode 100644 index 0000000000..92d26d3b72 --- /dev/null +++ b/deployment/lambdas/cf-url-rewriter/package-lock.json @@ -0,0 +1,63 @@ +{ + "name": "cf-url-rewriter", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "cf-url-rewriter", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@types/aws-lambda": "^8.10.68", + "@types/node": "^14.14.19", + "typescript": "^4.1.3" + } + }, + "node_modules/@types/aws-lambda": { + "version": "8.10.92", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.92.tgz", + "integrity": "sha512-dB14TltT1SNq73z3MaZfKyyBZ37NAgAFl8jze59bisR4fJ6pB6AYGxItHFkooZbN7UcVJX/cFudM4p8wp1W4rA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "14.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", + "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + } + }, + "dependencies": { + "@types/aws-lambda": { + "version": "8.10.92", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.92.tgz", + "integrity": "sha512-dB14TltT1SNq73z3MaZfKyyBZ37NAgAFl8jze59bisR4fJ6pB6AYGxItHFkooZbN7UcVJX/cFudM4p8wp1W4rA==", + "dev": true + }, + "@types/node": { + "version": "14.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", + "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", + "dev": true + }, + "typescript": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "dev": true + } + } +} diff --git a/deployment/lambdas/cf-url-rewriter/package.json b/deployment/lambdas/cf-url-rewriter/package.json new file mode 100644 index 0000000000..ad45bc7c9f --- /dev/null +++ b/deployment/lambdas/cf-url-rewriter/package.json @@ -0,0 +1,18 @@ +{ + "name": "cf-url-rewriter", + "version": "1.0.0", + "description": "", + "main": "cf-url-rewriter.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/aws-lambda": "^8.10.68", + "@types/node": "^14.14.19", + "typescript": "^4.1.3" + } + } + \ No newline at end of file diff --git a/deployment/lib/artifacts-public-access.ts b/deployment/lib/artifacts-public-access.ts index 23128c3d98..8c78b57200 100644 --- a/deployment/lib/artifacts-public-access.ts +++ b/deployment/lib/artifacts-public-access.ts @@ -1,8 +1,9 @@ import { - CloudFrontAllowedMethods, CloudFrontWebDistribution, LambdaEdgeEventType, OriginAccessIdentity, + CloudFrontAllowedMethods, CloudFrontWebDistribution, LambdaEdgeEventType, OriginAccessIdentity } from '@aws-cdk/aws-cloudfront'; import { CanonicalUserPrincipal, PolicyStatement } from '@aws-cdk/aws-iam'; -import { Code, Function, Runtime } from '@aws-cdk/aws-lambda'; +import { Architecture, Runtime } from '@aws-cdk/aws-lambda'; +import { NodejsFunction } from '@aws-cdk/aws-lambda-nodejs'; import { IBucket } from '@aws-cdk/aws-s3'; import { CfnOutput } from '@aws-cdk/core'; import { BuildArtifactStack } from './build-artifact-stack'; @@ -19,16 +20,15 @@ export class ArtifactsPublicAccess { principals: [new CanonicalUserPrincipal(originAccessIdentity.cloudFrontOriginAccessIdentityS3CanonicalUserId)], })); - // Incoming URLs from ci.opensearch.org will have a '/ci/123/' prefix, remove the prefix path from requests into S3. - const urlRewriter = new Function(stack, 'CfUrlRewriter', { - code: Code.fromInline(` - exports.handler = (event, context, callback) => { - const request = event.Records[0].cf.request; - request.uri = request.uri.replace(/^\\/ci\\/...\\//, '\\/') - callback(null, request); - };`), - handler: 'index.handler', + const urlRewriter = new NodejsFunction(stack, 'CfUrlRewriter', { runtime: Runtime.NODEJS_14_X, + entry: `${__dirname}/../lambdas/cf-url-rewriter/cf-url-rewriter.ts`, + handler: 'handler', + memorySize: 128, + architecture: Architecture.X86_64, + bundling: { + minify: true + } }); const distro = new CloudFrontWebDistribution(stack, 'CloudFrontBuildBucket', { diff --git a/deployment/package.json b/deployment/package.json index 1514a64fd5..7a03140875 100644 --- a/deployment/package.json +++ b/deployment/package.json @@ -13,6 +13,7 @@ }, "devDependencies": { "@aws-cdk/assert": "^1.123.0", + "@types/aws-lambda": "^8.10.92", "@types/jest": "^26.0.10", "@types/node": "10.17.27", "aws-cdk": "^1.123.0", @@ -22,13 +23,15 @@ "typescript": "~3.9.7" }, "dependencies": { - "@aws-cdk/aws-cloudfront": "^1.123.0", - "@aws-cdk/aws-iam": "^1.123.0", - "@aws-cdk/aws-lambda": "^1.123.0", - "@aws-cdk/aws-s3": "^1.123.0", - "@aws-cdk/core": "^1.123.0", + "@aws-cdk/aws-cloudfront": "1.145.0", + "@aws-cdk/aws-iam": "1.145.0", + "@aws-cdk/aws-lambda": "1.145.0", + "@aws-cdk/aws-lambda-nodejs": "1.145.0", + "@aws-cdk/aws-s3": "1.145.0", + "@aws-cdk/core": "1.145.0", "@typescript-eslint/eslint-plugin": "^4.31.1", "@typescript-eslint/parser": "^4.31.1", + "esbuild": "^0.14.23", "eslint": "^7.32.0", "eslint-config-airbnb-base": "^14.2.1", "eslint-plugin-import": "^2.24.2", diff --git a/deployment/test/build-artifact-stack.test.ts b/deployment/test/build-artifact-stack.test.ts index 89144b1391..4870af9602 100644 --- a/deployment/test/build-artifact-stack.test.ts +++ b/deployment/test/build-artifact-stack.test.ts @@ -15,6 +15,7 @@ test('Fresh BuildArtifact Stack', () => { expect(stack).to(countResources('AWS::IAM::Role', 4)); expect(stack).to(countResources('AWS::CloudFront::CloudFrontOriginAccessIdentity', 1)); expect(stack).to(countResources('AWS::CloudFront::Distribution', 1)); + expect(stack).to(countResources('AWS::Lambda::Function', 1)); expect(stack).to(haveOutput({ outputName: 'BuildDistributionDomainName' })); expect(stack).to(not(haveOutput({ outputName: 'OriginAccessIdentityS3Identifier' }))); }); @@ -30,6 +31,7 @@ test('Existing BuildArtifact Stack', () => { expect(stack).to(countResources('AWS::IAM::Role', 1)); expect(stack).to(countResources('AWS::CloudFront::CloudFrontOriginAccessIdentity', 1)); expect(stack).to(countResources('AWS::CloudFront::Distribution', 1)); + expect(stack).to(countResources('AWS::Lambda::Function', 1)); expect(stack).to(haveOutput({ outputName: 'BuildDistributionDomainName' })); expect(stack).to(haveOutput({ outputName: 'OriginAccessIdentityS3Identifier' })); }); diff --git a/deployment/test/lambdas/cf-url-rewriter/cf-url-rewriter.test.ts b/deployment/test/lambdas/cf-url-rewriter/cf-url-rewriter.test.ts new file mode 100644 index 0000000000..bb5aff53b8 --- /dev/null +++ b/deployment/test/lambdas/cf-url-rewriter/cf-url-rewriter.test.ts @@ -0,0 +1,20 @@ +import { CloudFrontRequest } from 'aws-lambda'; +import { handle } from "../../../lambdas/cf-url-rewriter/cf-url-rewriter"; + +test('Lmabda handle uri with ci string', () => { + + let request = { uri: '/ci/dbc/bundle-build-dashboards/1.2.0/428/linux/x64/' } as CloudFrontRequest; + + handle(request); + + expect(request.uri).toBe('/bundle-build-dashboards/1.2.0/428/linux/x64/'); +}); + +test('Lmabda handle uri without ci string', () => { + + let request = { uri: '/bundle-build-dashboards/1.2.0/428/linux/x64/' } as CloudFrontRequest; + + handle(request); + + expect(request.uri).toBe('/bundle-build-dashboards/1.2.0/428/linux/x64/'); +}); \ No newline at end of file