From 5661c146a96d74a9749bb6f2aba3a89fa7caa86e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20R=C3=B6pstorf?= Date: Sat, 10 Jun 2023 19:58:20 +0200 Subject: [PATCH 1/2] Adds php layer last in this.addLayers() call so that the php layer is added first This will allow passed in layers to extend the php layer --- src/function/PhpFpmFunction.ts | 4 ++-- src/function/PhpFunction.ts | 4 ++-- test/function/PhpFpmFunction.test.ts | 17 ++++++++++++++++- test/function/PhpFunction.test.ts | 17 ++++++++++++++++- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/function/PhpFpmFunction.ts b/src/function/PhpFpmFunction.ts index 37938b7..eea10df 100644 --- a/src/function/PhpFpmFunction.ts +++ b/src/function/PhpFpmFunction.ts @@ -42,9 +42,9 @@ export class PhpFpmFunction extends Function { } const phpVersion = props.phpVersion ?? functionDefaults.phpVersion; this.addLayers( - // Add the FPM layer first so that other layers can override it + ...layers, + // Add the FPM layer last so that other layers can override it fpmLayer(this, region, phpVersion, props.architecture ?? functionDefaults.architecture), - ...layers ); } } diff --git a/src/function/PhpFunction.ts b/src/function/PhpFunction.ts index 254cd1f..25c85e4 100644 --- a/src/function/PhpFunction.ts +++ b/src/function/PhpFunction.ts @@ -43,14 +43,14 @@ export class PhpFunction extends Function { } const phpVersion = props.phpVersion ?? functionDefaults.phpVersion; this.addLayers( - // Add the function layer first so that other layers can override it + ...layers, + // Add the function layer last so that other layers can override it functionLayer( this, region, phpVersion, props.architecture ?? functionDefaults.architecture ), - ...layers ); } } diff --git a/test/function/PhpFpmFunction.test.ts b/test/function/PhpFpmFunction.test.ts index 96c8322..51e19b5 100644 --- a/test/function/PhpFpmFunction.test.ts +++ b/test/function/PhpFpmFunction.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; import { PhpFpmFunction } from '../../src'; import { cleanupTemplate, compileTestStack } from '../helper'; -import { Architecture } from 'aws-cdk-lib/aws-lambda'; +import {Architecture, LayerVersion} from 'aws-cdk-lib/aws-lambda'; import { mapValues } from 'lodash'; describe('PhpFpmFunction', () => { @@ -37,4 +37,19 @@ describe('PhpFpmFunction', () => { template.resourceCountIs('AWS::Lambda::Function', 2); }); + + it('adds additional layer before php layer', () => { + const template = compileTestStack((stack) => { + new PhpFpmFunction(stack, 'Console', { + handler: 'index.php', + layers: [LayerVersion.fromLayerVersionArn(stack, 'Layer', 'arn:aws:lambda:us-east-1:123456789012:layer:layer-name:1')], + }); + }); + + const phpFunction = template.findResources('AWS::Lambda::Function'); + const layers = phpFunction.Console63CA37A7.Properties.Layers; + expect(layers).length(2); + expect(layers[1]).to.match(/arn:aws:lambda:us-east-1:534081306603:layer:php-81-fpm:\d+/); + expect(layers[0]).to.match(/arn:aws:lambda:us-east-1:123456789012:layer:layer-name:1/); + }); }); diff --git a/test/function/PhpFunction.test.ts b/test/function/PhpFunction.test.ts index 908adde..65ae823 100644 --- a/test/function/PhpFunction.test.ts +++ b/test/function/PhpFunction.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; import { PhpFunction } from '../../src'; import { cleanupTemplate, compileTestStack } from '../helper'; -import { Architecture } from 'aws-cdk-lib/aws-lambda'; +import {Architecture, LayerVersion} from 'aws-cdk-lib/aws-lambda'; import { mapValues } from 'lodash'; describe('PhpFunction', () => { @@ -44,4 +44,19 @@ describe('PhpFunction', () => { template.resourceCountIs('AWS::Lambda::Function', 2); }); + + it('adds additional layer before php layer', () => { + const template = compileTestStack((stack) => { + new PhpFunction(stack, 'Console', { + handler: 'index.php', + layers: [LayerVersion.fromLayerVersionArn(stack, 'Layer', 'arn:aws:lambda:us-east-1:123456789012:layer:layer-name:1')], + }); + }); + + const phpFunction = template.findResources('AWS::Lambda::Function'); + const layers = phpFunction.Console63CA37A7.Properties.Layers; + expect(layers).length(2); + expect(layers[1]).to.match(/arn:aws:lambda:us-east-1:534081306603:layer:php-81:\d+/); + expect(layers[0]).to.match(/arn:aws:lambda:us-east-1:123456789012:layer:layer-name:1/); + }); }); From 110106f999dd8166866b813bd7503acfe611b343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20R=C3=B6pstorf?= Date: Sat, 10 Jun 2023 19:58:49 +0200 Subject: [PATCH 2/2] Adds phpLayer last and consoleLayer first and then other passed in layers ConsoleFunction will now extend the cdk construct Function instead of PhpFunction: Without remodelling the functions themselves, this was the easiest pick but it does duplicate nearly all logic from the PhpFunction itself --- src/function/ConsoleFunction.ts | 50 +++++++++++++++++++++++---- test/function/ConsoleFunction.test.ts | 22 ++++++++++-- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/function/ConsoleFunction.ts b/src/function/ConsoleFunction.ts index 139393e..7b2c819 100644 --- a/src/function/ConsoleFunction.ts +++ b/src/function/ConsoleFunction.ts @@ -1,12 +1,48 @@ -import { Stack } from 'aws-cdk-lib'; +import {Duration, Stack} from 'aws-cdk-lib'; import { Construct } from 'constructs'; -import { consoleLayer } from '../layers'; -import { PhpFunction, PhpFunctionProps } from './PhpFunction'; +import {consoleLayer, functionLayer} from '../layers'; +import {Function, FunctionProps, Runtime} from "aws-cdk-lib/aws-lambda"; +import {IVpc} from "aws-cdk-lib/aws-ec2"; +import {VpcForServerlessApp} from "../vpc/VpcForServerlessApp"; +import {functionDefaults, vpcDefaults} from "./defaults"; +import {packagePhpCode} from "../package"; -export class ConsoleFunction extends PhpFunction { - constructor(scope: Construct, id: string, props: PhpFunctionProps) { - super(scope, id, props); +export type PhpConsoleFunctionProps = Partial & { + phpVersion?: '8.0' | '8.1' | '8.2'; + handler: string; + vpc?: IVpc | VpcForServerlessApp; +}; - this.addLayers(consoleLayer(this, Stack.of(scope).region)); +export class ConsoleFunction extends Function { + constructor(scope: Construct, id: string, props: PhpConsoleFunctionProps) { + const defaults = { + runtime: Runtime.PROVIDED_AL2, + code: props.code ?? packagePhpCode(), + timeout: Duration.seconds(6), + memorySize: functionDefaults.memorySize, + }; + + const layers = props.layers ?? []; + + super(scope, id, { + ...props, + ...vpcDefaults(props.vpc), + layers: [], + ...defaults, + }); + + this.addLayers( + ...layers, + consoleLayer( + this, + Stack.of(scope).region + ), + // Adds the function layer last so that others(in this case console depends on it) can override it + functionLayer( + this, + Stack.of(scope).region, + props.phpVersion ?? functionDefaults.phpVersion, + props.architecture ?? functionDefaults.architecture) + ); } } diff --git a/test/function/ConsoleFunction.test.ts b/test/function/ConsoleFunction.test.ts index 6ccb66e..b6c87e1 100644 --- a/test/function/ConsoleFunction.test.ts +++ b/test/function/ConsoleFunction.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; import { ConsoleFunction } from '../../src'; import { compileTestStack } from '../helper'; -import { Architecture } from 'aws-cdk-lib/aws-lambda'; +import {Architecture, LayerVersion} from 'aws-cdk-lib/aws-lambda'; import { mapValues } from 'lodash'; describe('ConsoleFunction', () => { @@ -15,8 +15,24 @@ describe('ConsoleFunction', () => { const consoleFunction = template.findResources('AWS::Lambda::Function'); const layers = consoleFunction.Console63CA37A7.Properties.Layers; expect(layers).length(2); - expect(layers[0]).to.match(/arn:aws:lambda:us-east-1:534081306603:layer:php-81:\d+/); + expect(layers[1]).to.match(/arn:aws:lambda:us-east-1:534081306603:layer:php-81:\d+/); + expect(layers[0]).to.match(/arn:aws:lambda:us-east-1:534081306603:layer:console:\d+/); + }); + + it('adds additional layers before console and php layer', () => { + const template = compileTestStack((stack) => { + new ConsoleFunction(stack, 'Console', { + handler: 'index.php', + layers: [LayerVersion.fromLayerVersionArn(stack, 'Layer', 'arn:aws:lambda:us-east-1:123456789012:layer:layer-name:1')], + }); + }); + + const consoleFunction = template.findResources('AWS::Lambda::Function'); + const layers = consoleFunction.Console63CA37A7.Properties.Layers; + expect(layers).length(3); + expect(layers[2]).to.match(/arn:aws:lambda:us-east-1:534081306603:layer:php-81:\d+/); expect(layers[1]).to.match(/arn:aws:lambda:us-east-1:534081306603:layer:console:\d+/); + expect(layers[0]).to.match(/arn:aws:lambda:us-east-1:123456789012:layer:layer-name:1/); }); it('supports ARM', () => { @@ -29,7 +45,7 @@ describe('ConsoleFunction', () => { mapValues(template.findResources('AWS::Lambda::Function'), (resource) => { expect(resource.Properties.Architectures).toEqual(['arm64']); - expect(resource.Properties.Layers[0]).matches( + expect(resource.Properties.Layers[1]).matches( /arn:aws:lambda:us-east-1:534081306603:layer:arm-php-81:\d+/ ); });