Skip to content

Commit

Permalink
fix(lambda): adds missing deploy-time deps for lambda with efs
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Neilson committed Apr 28, 2021
1 parent 2f5eeb0 commit 708c3bd
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 0 deletions.
21 changes: 21 additions & 0 deletions packages/@aws-cdk/aws-lambda/lib/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,23 @@ export class Function extends FunctionBase {
if (config.dependency) {
this.node.addDependency(...config.dependency);
}
// There could be a race if the Lambda is used in a CustomResource. It is possible for the Lambda to
// fail to attach to a given FileSystem if we do not have a dependency on the SecurityGroup ingress/egress
// rules that were created between this Lambda's SG & the Filesystem SG.
this.connections.securityGroups.forEach(sg => {
sg.node.findAll().forEach(child => {
if (child instanceof CfnResource && child.cfnResourceType === 'AWS::EC2::SecurityGroupEgress') {
resource.node.addDependency(child);
}
});
});
config.connections?.securityGroups.forEach(sg => {
sg.node.findAll().forEach(child => {
if (child instanceof CfnResource && child.cfnResourceType === 'AWS::EC2::SecurityGroupIngress') {
resource.node.addDependency(child);
}
});
});
}
}

Expand Down Expand Up @@ -856,6 +873,10 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett
throw new Error('Cannot configure \'securityGroup\' or \'allowAllOutbound\' without configuring a VPC');
}

if (!props.vpc && props.filesystem) {
throw new Error('Cannot configurea \'filesystem\' without configuring a VPC.');
}

if (!props.vpc) { return undefined; }

if (props.securityGroup && props.allowAllOutbound !== undefined) {
Expand Down
64 changes: 64 additions & 0 deletions packages/@aws-cdk/aws-lambda/test/function.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1841,6 +1841,7 @@ describe('function', () => {
const accessPoint = fs.addAccessPoint('AccessPoint');
// WHEN
new lambda.Function(stack, 'MyFunction', {
vpc,
handler: 'foo',
runtime: lambda.Runtime.NODEJS_12_X,
code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')),
Expand Down Expand Up @@ -1879,6 +1880,69 @@ describe('function', () => {
],
});
});

test('throw error mounting efs with no vpc', () => {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'Vpc', {
maxAzs: 3,
natGateways: 1,
});

const fs = new efs.FileSystem(stack, 'Efs', {
vpc,
});
const accessPoint = fs.addAccessPoint('AccessPoint');

// THEN
expect(() => {
new lambda.Function(stack, 'MyFunction', {
handler: 'foo',
runtime: lambda.Runtime.NODEJS_12_X,
code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')),
filesystem: lambda.FileSystem.fromEfsAccessPoint(accessPoint, '/mnt/msg'),
});
}).toThrow();
});

test('verify deps when mounting efs', () => {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'Vpc', {
maxAzs: 3,
natGateways: 1,
});
const securityGroup = new ec2.SecurityGroup(stack, 'LambdaSG', {
vpc,
allowAllOutbound: false,
});

const fs = new efs.FileSystem(stack, 'Efs', {
vpc,
});
const accessPoint = fs.addAccessPoint('AccessPoint');
// WHEN
new lambda.Function(stack, 'MyFunction', {
vpc,
handler: 'foo',
securityGroups: [securityGroup],
runtime: lambda.Runtime.NODEJS_12_X,
code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')),
filesystem: lambda.FileSystem.fromEfsAccessPoint(accessPoint, '/mnt/msg'),
});

// THEN
expect(stack).toHaveResource('AWS::Lambda::Function', {
DependsOn: [
'EfsEfsMountTarget195B2DD2E',
'EfsEfsMountTarget2315C927F',
'EfsEfsSecurityGroupfromLambdaSG20491B2F751D',
'LambdaSGtoEfsEfsSecurityGroupFCE2954020499719694A',
'MyFunctionServiceRoleDefaultPolicyB705ABD4',
'MyFunctionServiceRole3C357FF2',
],
}, ResourcePart.CompleteDefinition);
});
});

describe('code config', () => {
Expand Down

0 comments on commit 708c3bd

Please sign in to comment.