Skip to content

Commit

Permalink
Merge pull request #3637 from aws/release-v1.90.0
Browse files Browse the repository at this point in the history
Release 1.90.0 (to main)
  • Loading branch information
paulhcsun authored Aug 14, 2024
2 parents 44562dc + b86f1c5 commit 690bfff
Show file tree
Hide file tree
Showing 53 changed files with 3,686 additions and 1,063 deletions.
1 change: 1 addition & 0 deletions .cfnlintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ ignore_templates:
- tests/translator/output/**/function_with_event_dest_conditional.json
- tests/translator/output/**/function_with_event_schedule_state.json
- tests/translator/output/**/function_with_file_system_config.json
- tests/translator/output/**/function_with_event_filtering.json # TODO: remove once Event's KmsKeyArn is available
- tests/translator/output/**/function_with_function_url_config_conditions.json
- tests/translator/output/**/function_with_globals_role_path.json
- tests/translator/output/**/function_with_intrinsic_architecture.json
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ black-check:
make format-check

lint:
ruff samtranslator bin schema_source integration tests
ruff check samtranslator bin schema_source integration tests
# mypy performs type check
mypy --strict samtranslator bin schema_source
# cfn-lint to make sure generated CloudFormation makes sense
bin/run_cfn_lint.sh

lint-fix:
ruff --fix samtranslator bin schema_source integration tests
ruff check --fix samtranslator bin schema_source integration tests

prepare-companion-stack:
pytest -v --no-cov integration/setup -m setup
Expand Down
33 changes: 0 additions & 33 deletions integration/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
import time
from pathlib import Path

import boto3
Expand Down Expand Up @@ -61,29 +60,6 @@ def clean_all_integ_buckets():
clean_bucket(bucket.name, s3_client)


def _delete_unused_network_interface_by_subnet(ec2_client, subnet_id):
"""Deletes unused network interface under the provided subnet"""
paginator = ec2_client.get_paginator("describe_network_interfaces")
response_iterator = paginator.paginate(
Filters=[
{"Name": "subnet-id", "Values": [subnet_id]},
{"Name": "status", "Values": ["available"]},
]
)
network_interface_ids = []
for page in response_iterator:
network_interface_ids += [ni["NetworkInterfaceId"] for ni in page["NetworkInterfaces"]]

for ni_id in network_interface_ids:
try:
ec2_client.delete_network_interface(NetworkInterfaceId=ni_id)
except ClientError as e:
LOG.error("Unable to delete network interface %s", ni_id, exc_info=e)
time.sleep(0.5)

LOG.info("Deleted %s unused network interfaces under subnet %s", len(network_interface_ids), subnet_id)


@pytest.fixture()
def setup_companion_stack_once(tmpdir_factory, get_prefix):
tests_integ_dir = Path(__file__).resolve().parents[1]
Expand All @@ -95,15 +71,6 @@ def setup_companion_stack_once(tmpdir_factory, get_prefix):
companion_stack = Stack(stack_name, companion_stack_tempalte_path, cfn_client, output_dir)
companion_stack.create_or_update(_stack_exists(stack_name))

ec2_client = ClientProvider().ec2_client
precreated_subnet_ids = [
resource["PhysicalResourceId"]
for resource in companion_stack.stack_resources["StackResourceSummaries"]
if resource["LogicalResourceId"].startswith("PreCreatedSubnet")
]
for subnet_id in precreated_subnet_ids:
_delete_unused_network_interface_by_subnet(ec2_client, subnet_id)


@pytest.fixture()
def get_serverless_application_repository_app():
Expand Down
15 changes: 10 additions & 5 deletions integration/helpers/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,9 +567,9 @@ def verify_options_request(self, url, expected_status_code, headers=None):
)
return response

def verify_post_request(self, url: str, body_obj, expected_status_code: int):
def verify_post_request(self, url: str, body_obj, expected_status_code: int, headers=None):
"""Return response to POST request and verify matches expected status code."""
response = self.do_post_request(url, body_obj)
response = self.do_post_request_with_logging(url, body_obj, headers)
if response.status_code != expected_status_code:
raise StatusCodeError(
f"Request to {url} failed with status: {response.status_code}, expected status: {expected_status_code}"
Expand Down Expand Up @@ -650,12 +650,17 @@ def do_options_request_with_logging(self, url, headers=None):
)
return response

def do_post_request(self, url: str, body_obj):
def do_post_request_with_logging(self, url: str, body_obj, requestHeaders=None):
"""Perform a POST request with dict body body_obj."""
response = requests.post(url, json=body_obj)
response = (
requests.post(url, json=body_obj, headers=requestHeaders)
if requestHeaders
else requests.post(url, json=body_obj)
)
amazon_headers = RequestUtils(response).get_amazon_headers()
if self.internal:
REQUEST_LOGGER.info(
"POST request made to " + url,
extra={"test": self.testcase, "status": response.status_code},
extra={"test": self.testcase, "status": response.status_code, "headers": amazon_headers},
)
return response
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"LogicalResourceId": "BasicFunctionWithEventFilteringUsingKmsKeyArn",
"ResourceType": "AWS::Lambda::Function"
},
{
"LogicalResourceId": "BasicFunctionWithEventFilteringUsingKmsKeyArnRole",
"ResourceType": "AWS::IAM::Role"
},
{
"LogicalResourceId": "MyKey",
"ResourceType": "AWS::KMS::Key"
},
{
"LogicalResourceId": "MySqsQueue",
"ResourceType": "AWS::SQS::Queue"
},
{
"LogicalResourceId": "BasicFunctionWithEventFilteringUsingKmsKeyArnMySqsEvent",
"ResourceType": "AWS::Lambda::EventSourceMapping"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
Resources:
BasicFunctionWithEventFilteringUsingKmsKeyArn:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs18.x
CodeUri: ${codeuri}
MemorySize: 128
Events:
MySqsEvent:
Type: SQS
Properties:
Queue: !GetAtt MySqsQueue.Arn
FilterCriteria:
Filters:
- Pattern: '{ "body" : { "RequestCode" : [ "BBBB" ] } }'
KmsKeyArn: !GetAtt MyKey.Arn

MyKey:
Type: AWS::KMS::Key
Properties:
Description: A sample key
KeyPolicy:
Version: '2012-10-17'
Id: key-default-1
Statement:
- Sid: Allow administration of the key
Effect: Allow
Principal:
AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root
Action:
- kms:*
Resource: '*'
- Sid: Allow encryption/decryption access to Lambda Service Principal
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: kms:Decrypt
Resource: '*'

MySqsQueue:
Type: AWS::SQS::Queue

Metadata:
SamTransformTest: true
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Resources:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
EndpointConfiguration:
Type: REGIONAL
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
Expand Down
10 changes: 5 additions & 5 deletions integration/ruff.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# black formatter takes care of the line length
line-length = 999

# Mininal python version we support is 3.8
target-version = "py38"

# The code quality of tests can be a bit lower compared to samtranslator
select = [
lint.select = [
"E", # Pyflakes
"F", # Pyflakes
"PL", # pylint
Expand All @@ -15,10 +18,7 @@ select = [
"UP", # pyupgrade
]

# Mininal python version we support is 3.8
target-version = "py38"

[per-file-ignores]
[lint.per-file-ignores]

# The code quality of tests can be a bit lower:
"**/*.py" = [
Expand Down
4 changes: 4 additions & 0 deletions integration/single/test_basic_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ def test_state_machine_with_api_single_quotes_input(self):
"""
Pass single quotes in input JSON to a StateMachine
See https://github.com/aws/serverless-application-model/issues/1895
This test is known to sometimes be flaky, but we want to avoid marking it as non-blocking as this is a basic api test.
Instead, we set the EndpointConfiguration to REGIONAL and added logging to the api request
If this test continues to fail it should be marked as non-blocking
"""
self.create_and_verify_stack("single/state_machine_with_api")

Expand Down
22 changes: 22 additions & 0 deletions integration/single/test_basic_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,28 @@ def test_basic_function_with_tracing(self):
"Expecting tracing config mode to be set to PassThrough.",
)

# TODO: add the integration test back after the feature launch on 06/05
# @skipIf(current_region_does_not_support([KMS]), "KMS is not supported in this testing region")
# def test_basic_function_with_event_filtering_using_kms(self):
# """
# Creates a basic lambda function with KMS key arn
# """
# self.create_and_verify_stack("single/basic_function_with_event_filtering_using_kms")

# lambda_function_name = self.get_physical_id_by_type("AWS::Lambda::Function")
# event_source_mappings = self.client_provider.lambda_client.list_event_source_mappings(
# FunctionName=lambda_function_name
# )

# event_source_mapping = event_source_mappings["EventSourceMappings"][0]
# function_uuid = event_source_mapping["UUID"]

# event_source_mapping_config = self.client_provider.lambda_client.get_event_source_mapping(UUID=function_uuid)

# kms_key_arn = event_source_mapping_config["KMSKeyArn"]

# self.assertIsNotNone(kms_key_arn, "Expecting KmsKeyArn to be set.")

def _assert_invoke(self, lambda_client, function_name, qualifier=None, expected_status_code=200):
"""
Assert if a Lambda invocation returns the expected status code
Expand Down
3 changes: 2 additions & 1 deletion requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ jsonschema<5,>=3.2 # TODO: evaluate risk of removing jsonschema 3.x support
typing_extensions>=4.4 # 3.8 doesn't have Required, TypeGuard and ParamSpec

# resource validation & schema generation
pydantic>=1.8,<3
# 1.10.15 and 1.10.17 included breaking change from pydantic, more info: https://github.com/aws/serverless-application-model/issues/3617
pydantic>=1.8,<3,!=1.10.15,!=1.10.17
2 changes: 1 addition & 1 deletion requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pytest-xdist>=2.5,<4
pytest-env>=0.6,<1
pytest-rerunfailures>=9.1,<12
pyyaml~=6.0
ruff~=0.1.0
ruff~=0.4.5

# Test requirements
pytest>=6.2,<8
Expand Down
14 changes: 7 additions & 7 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# black formatter takes care of the line length
line-length = 999

select = [
# Mininal python version we support is 3.8
target-version = "py38"

lint.select = [
"E", # pycodestyle
"W", # pycodestyle
"F", # Pyflakes
Expand All @@ -27,7 +30,7 @@ select = [
"T20", # flake8-print
]

ignore = [
lint.ignore = [
"UP006", # https://github.com/charliermarsh/ruff/pull/4427
"UP007", # https://github.com/charliermarsh/ruff/pull/4427
# Mutable class attributes should be annotated with `typing.ClassVar`
Expand All @@ -37,10 +40,7 @@ ignore = [
"G004",
]

# Mininal python version we support is 3.8
target-version = "py38"

[per-file-ignores]
[lint.per-file-ignores]
# python scripts in bin/ needs some python path configurations before import
"bin/*.py" = [
# E402: module-import-not-at-top-of-file
Expand All @@ -53,5 +53,5 @@ target-version = "py38"
"T201",
]

[pylint]
[lint.pylint]
max-args = 6 # We have many functions reaching 6 args
2 changes: 1 addition & 1 deletion samtranslator/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.89.0"
__version__ = "1.90.0"
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ class KinesisEventProperties(BaseModel):
Enabled: Optional[PassThroughProp] = kinesiseventproperties("Enabled")
FilterCriteria: Optional[PassThroughProp] = kinesiseventproperties("FilterCriteria")
FunctionResponseTypes: Optional[PassThroughProp] = kinesiseventproperties("FunctionResponseTypes")
KmsKeyArn: Optional[PassThroughProp] # TODO: add documentation
MaximumBatchingWindowInSeconds: Optional[PassThroughProp] = kinesiseventproperties("MaximumBatchingWindowInSeconds")
MaximumRecordAgeInSeconds: Optional[PassThroughProp] = kinesiseventproperties("MaximumRecordAgeInSeconds")
MaximumRetryAttempts: Optional[PassThroughProp] = kinesiseventproperties("MaximumRetryAttempts")
Expand All @@ -191,6 +192,7 @@ class DynamoDBEventProperties(BaseModel):
Enabled: Optional[PassThroughProp] = dynamodbeventproperties("Enabled")
FilterCriteria: Optional[PassThroughProp] = dynamodbeventproperties("FilterCriteria")
FunctionResponseTypes: Optional[PassThroughProp] = dynamodbeventproperties("FunctionResponseTypes")
KmsKeyArn: Optional[PassThroughProp] # TODO: add documentation
MaximumBatchingWindowInSeconds: Optional[PassThroughProp] = dynamodbeventproperties(
"MaximumBatchingWindowInSeconds"
)
Expand Down Expand Up @@ -235,6 +237,7 @@ class SQSEventProperties(BaseModel):
Enabled: Optional[PassThroughProp] = sqseventproperties("Enabled")
FilterCriteria: Optional[PassThroughProp] = sqseventproperties("FilterCriteria")
FunctionResponseTypes: Optional[PassThroughProp] = sqseventproperties("FunctionResponseTypes")
KmsKeyArn: Optional[PassThroughProp] # TODO: add documentation
MaximumBatchingWindowInSeconds: Optional[PassThroughProp] = sqseventproperties("MaximumBatchingWindowInSeconds")
Queue: PassThroughProp = sqseventproperties("Queue")
ScalingConfig: Optional[PassThroughProp] # Update docs when live
Expand Down Expand Up @@ -406,6 +409,7 @@ class HttpApiEvent(BaseModel):
class MSKEventProperties(BaseModel):
ConsumerGroupId: Optional[PassThroughProp] = mskeventproperties("ConsumerGroupId")
FilterCriteria: Optional[PassThroughProp] = mskeventproperties("FilterCriteria")
KmsKeyArn: Optional[PassThroughProp] # TODO: add documentation
MaximumBatchingWindowInSeconds: Optional[PassThroughProp] = mskeventproperties("MaximumBatchingWindowInSeconds")
StartingPosition: Optional[PassThroughProp] = mskeventproperties("StartingPosition")
StartingPositionTimestamp: Optional[PassThroughProp] = mskeventproperties("StartingPositionTimestamp")
Expand All @@ -426,6 +430,7 @@ class MQEventProperties(BaseModel):
DynamicPolicyName: Optional[bool] = mqeventproperties("DynamicPolicyName")
Enabled: Optional[PassThroughProp] = mqeventproperties("Enabled")
FilterCriteria: Optional[PassThroughProp] = mqeventproperties("FilterCriteria")
KmsKeyArn: Optional[PassThroughProp] # TODO: add documentation
MaximumBatchingWindowInSeconds: Optional[PassThroughProp] = mqeventproperties("MaximumBatchingWindowInSeconds")
Queues: PassThroughProp = mqeventproperties("Queues")
SecretsManagerKmsKeyId: Optional[str] = mqeventproperties("SecretsManagerKmsKeyId")
Expand All @@ -445,6 +450,7 @@ class SelfManagedKafkaEventProperties(BaseModel):
KafkaBootstrapServers: Optional[List[SamIntrinsicable[str]]] = selfmanagedkafkaeventproperties(
"KafkaBootstrapServers"
)
KmsKeyArn: Optional[PassThroughProp] # TODO: add documentation
SourceAccessConfigurations: PassThroughProp = selfmanagedkafkaeventproperties("SourceAccessConfigurations")
StartingPosition: Optional[PassThroughProp] # TODO: add documentation
StartingPositionTimestamp: Optional[PassThroughProp] # TODO: add documentation
Expand Down
3 changes: 1 addition & 2 deletions samtranslator/model/api/http_api_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,7 @@ def _get_authorizers(
if "OpenIdConnectUrl" in authorizer:
raise InvalidResourceException(
self.logical_id,
"'OpenIdConnectUrl' is no longer a supported property for authorizer '%s'. Please refer to the AWS SAM documentation."
% (authorizer_name),
f"'OpenIdConnectUrl' is no longer a supported property for authorizer '{authorizer_name}'. Please refer to the AWS SAM documentation.",
)
authorizers[authorizer_name] = ApiGatewayV2Authorizer( # type: ignore[no-untyped-call]
api_logical_id=self.logical_id,
Expand Down
5 changes: 2 additions & 3 deletions samtranslator/model/apigatewayv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class ApiGatewayV2HttpApi(Resource):
}

runtime_attrs = {"http_api_id": lambda self: ref(self.logical_id)}
Tags: Optional[PassThrough]

def assign_tags(self, tags: Dict[str, Any]) -> None:
"""Overriding default 'assign_tags' function in Resource class
Expand All @@ -34,8 +33,8 @@ def assign_tags(self, tags: Dict[str, Any]) -> None:
:param tags: Tags to be assigned to the resource
"""
if tags is not None and "Tags" in self.property_types:
self.Tags = tags
# Tags are already defined in Body so they do not need to be assigned here
return


class ApiGatewayV2Stage(Resource):
Expand Down
Loading

0 comments on commit 690bfff

Please sign in to comment.