Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions integration/combination/test_function_with_capacity_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from unittest.case import skipIf

import pytest

from integration.config.service_names import LAMBDA_MANAGED_INSTANCES
from integration.helpers.base_test import BaseTest
from integration.helpers.resource import current_region_does_not_support


@skipIf(
current_region_does_not_support([LAMBDA_MANAGED_INSTANCES]),
"LambdaManagedInstance is not supported in this testing region",
)
class TestFunctionWithCapacityProvider(BaseTest):
@pytest.fixture(autouse=True)
def companion_stack_outputs(self, get_companion_stack_outputs):
self.companion_stack_outputs = get_companion_stack_outputs

def test_function_with_capacity_provider_custom_role(self):
"""Test Lambda function with CapacityProviderConfig using custom operator role."""
# Phase 1: Prepare parameters from companion stack
parameters = [
self.generate_parameter("SubnetId", self.companion_stack_outputs["LMISubnetId"]),
self.generate_parameter("SecurityGroup", self.companion_stack_outputs["LMISecurityGroupId"]),
self.generate_parameter("KMSKeyArn", self.companion_stack_outputs["LMIKMSKeyArn"]),
]

# Phase 2: Deploy and verify against expected JSON
self.create_and_verify_stack("combination/function_lmi_custom", parameters)

# Phase 3: Verify resource counts
lambda_resources = self.get_stack_resources("AWS::Lambda::Function")
self.assertEqual(len(lambda_resources), 1, "Should create exactly one Lambda function")

capacity_provider_resources = self.get_stack_resources("AWS::Lambda::CapacityProvider")
self.assertEqual(len(capacity_provider_resources), 1, "Should create exactly one CapacityProvider")

iam_role_resources = self.get_stack_resources("AWS::IAM::Role")
self.assertEqual(len(iam_role_resources), 2, "Should create exactly two IAM roles")

def test_function_with_capacity_provider_default_role(self):
"""Test Lambda function with CapacityProviderConfig using default operator role."""
# Phase 1: Prepare parameters from companion stack
parameters = [
self.generate_parameter("SubnetId", self.companion_stack_outputs["LMISubnetId"]),
self.generate_parameter("SecurityGroup", self.companion_stack_outputs["LMISecurityGroupId"]),
self.generate_parameter("KMSKeyArn", self.companion_stack_outputs["LMIKMSKeyArn"]),
]

# Phase 2: Deploy and verify against expected JSON
self.create_and_verify_stack("combination/function_lmi_default", parameters)

# Phase 3: Verify resource counts
lambda_resources = self.get_stack_resources("AWS::Lambda::Function")
self.assertEqual(len(lambda_resources), 1, "Should create exactly one Lambda function")

capacity_provider_resources = self.get_stack_resources("AWS::Lambda::CapacityProvider")
self.assertEqual(len(capacity_provider_resources), 2, "Should create exactly two CapacityProviders")

iam_role_resources = self.get_stack_resources("AWS::IAM::Role")
self.assertEqual(len(iam_role_resources), 3, "Should create exactly three IAM roles")
1 change: 1 addition & 0 deletions integration/config/service_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
STATE_MACHINE_CWE_CWS = "StateMachineCweCws"
STATE_MACHINE_WITH_APIS = "StateMachineWithApis"
LAMBDA_URL = "LambdaUrl"
LAMBDA_MANAGED_INSTANCES = "LambdaManagedInstances"
LAMBDA_ENV_VARS = "LambdaEnvVars"
EVENT_INVOKE_CONFIG = "EventInvokeConfig"
API_KEY = "ApiKey"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyCapacityProvider",
"ResourceType": "AWS::Lambda::CapacityProvider"
},
{
"LogicalResourceId": "MyCapacityProviderCustomRole",
"ResourceType": "AWS::IAM::Role"
},
{
"LogicalResourceId": "MyFunction",
"ResourceType": "AWS::Lambda::Function"
},
{
"LogicalResourceId": "MyFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[
{
"LogicalResourceId": "SimpleCapacityProvider",
"ResourceType": "AWS::Lambda::CapacityProvider"
},
{
"LogicalResourceId": "SimpleCapacityProviderOperatorRole",
"ResourceType": "AWS::IAM::Role"
},
{
"LogicalResourceId": "AdvancedCapacityProvider",
"ResourceType": "AWS::Lambda::CapacityProvider"
},
{
"LogicalResourceId": "AdvancedCapacityProviderOperatorRole",
"ResourceType": "AWS::IAM::Role"
},
{
"LogicalResourceId": "MyFunction",
"ResourceType": "AWS::Lambda::Function"
},
{
"LogicalResourceId": "MyFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
Parameters:
SubnetId:
Type: String
SecurityGroup:
Type: String
KMSKeyArn:
Type: String

Resources:
MyCapacityProviderCustomRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: CapacityProviderOperatorRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- ec2:AttachNetworkInterface
- ec2:CreateTags
- ec2:RunInstances
Resource:
- !Sub arn:${AWS::Partition}:ec2:*:*:instance/*
- !Sub arn:${AWS::Partition}:ec2:*:*:network-interface/*
- !Sub arn:${AWS::Partition}:ec2:*:*:volume/*
Condition:
StringEquals:
ec2:ManagedResourceOperator: scaler.lambda.amazonaws.com
- Effect: Allow
Action:
- ec2:DescribeAvailabilityZones
- ec2:DescribeCapacityReservations
- ec2:DescribeInstances
- ec2:DescribeInstanceStatus
- ec2:DescribeInstanceTypeOfferings
- ec2:DescribeInstanceTypes
- ec2:DescribeSecurityGroups
- ec2:DescribeSubnets
Resource: '*'
- Effect: Allow
Action:
- ec2:RunInstances
- ec2:CreateNetworkInterface
Resource:
- !Sub arn:${AWS::Partition}:ec2:*:*:subnet/*
- !Sub arn:${AWS::Partition}:ec2:*:*:security-group/*
- Effect: Allow
Action:
- ec2:RunInstances
Resource:
- !Sub arn:${AWS::Partition}:ec2:*:*:image/*
Condition:
Bool:
ec2:Public: 'true'

MyCapacityProvider:
Type: AWS::Serverless::CapacityProvider
Properties:
CapacityProviderName: !Sub "${AWS::StackName}-cp"
VpcConfig:
SubnetIds:
- !Ref SubnetId
SecurityGroupIds:
- !Ref SecurityGroup
OperatorRole: !GetAtt MyCapacityProviderCustomRole.Arn

MyFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs22.x
Handler: index.handler
CodeUri: ${codeuri}
CapacityProviderConfig:
Arn: !GetAtt MyCapacityProvider.Arn

Metadata:
SamTransformTest: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
Parameters:
SubnetId:
Type: String
SecurityGroup:
Type: String
KMSKeyArn:
Type: String

Resources:
SimpleCapacityProvider:
Type: AWS::Serverless::CapacityProvider
Properties:
VpcConfig:
SubnetIds:
- !Ref SubnetId
SecurityGroupIds:
- !Ref SecurityGroup

MyFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs22.x
Handler: index.handler
CodeUri: ${codeuri}
CapacityProviderConfig:
Arn: !GetAtt SimpleCapacityProvider.Arn

AdvancedCapacityProvider:
Type: AWS::Serverless::CapacityProvider
Properties:
CapacityProviderName: !Sub "${AWS::StackName}-cp"
VpcConfig:
SubnetIds:
- !Ref SubnetId
SecurityGroupIds:
- !Ref SecurityGroup
InstanceRequirements:
Architectures:
- x86_64
AllowedTypes:
- m5.large
- m5.xlarge
- m5.2xlarge
ScalingConfig:
MaxVCpuCount: 64
AverageCPUUtilization: 70
KmsKeyArn: !Ref KMSKeyArn
Tags:
Environment: Test

Metadata:
SamTransformTest: true
109 changes: 109 additions & 0 deletions integration/setup/companion-stack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,106 @@ Resources:
Type: AWS::S3::Bucket
DeletionPolicy: Delete

LMIKMSKey:
Type: AWS::KMS::Key
Properties:
Description: KMS Key for Lambda Capacity Provider Resource
KeyPolicy:
Version: '2012-10-17'
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:root"
Action: kms:*
Resource: '*'
- Sid: Allow Lambda service
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action:
- kms:Decrypt
- kms:DescribeKey
Resource: '*' # Lambda Managed Instances (LMI) VPC Resources

LMIVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-VPC"

LMIPrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref LMIVpc
CidrBlock: 10.0.1.0/24
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-PrivateSubnet"

LMIPrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref LMIVpc
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-PrivateRT"

LMIPrivateSubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref LMIPrivateSubnet
RouteTableId: !Ref LMIPrivateRouteTable

LMISecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for capacity provider Lambda functions
VpcId: !Ref LMIVpc
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 10.0.0.0/16
Description: Allow HTTPS within VPC
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-LambdaSG"

VPCEndpointSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for VPC endpoints
VpcId: !Ref LMIVpc
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 10.0.0.0/16
Description: Allow HTTPS from within VPC
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-VPCEndpointSG"

CloudWatchLogsEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref LMIVpc
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.logs'
VpcEndpointType: Interface
PrivateDnsEnabled: true
SubnetIds:
- !Ref LMIPrivateSubnet
SecurityGroupIds:
- !Ref VPCEndpointSecurityGroup
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-CloudWatchLogsEndpoint"
Outputs:
PreCreatedVpc:
Description: Pre-created VPC that can be used inside other tests
Expand All @@ -66,5 +166,14 @@ Outputs:
Description: Pre-created S3 Bucket that can be used inside other tests
Value:
Ref: PreCreatedS3Bucket
LMISubnetId:
Description: Private subnet ID for Lambda functions
Value: !Ref LMIPrivateSubnet
LMISecurityGroupId:
Description: Security group ID for Lambda functions
Value: !Ref LMISecurityGroup
LMIKMSKeyArn:
Description: ARN of the KMS key for Capacity Provider
Value: !GetAtt LMIKMSKey.Arn
Metadata:
SamTransformTest: true
Loading