10000 Fix: CFn: support tags with ESMs by simonrw · Pull Request #11787 · localstack/localstack · GitHub
[go: up one dir, main page]

Skip to content

Fix: CFn: support tags with ESMs #11787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 7, 2024
Merged
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# LocalStack Resource Provider Scaffolding v2
from __future__ import annotations

import copy
from pathlib import Path
from typing import Optional, TypedDict

Expand Down Expand Up @@ -126,8 +127,16 @@ def create(
model = request.desired_state
lambda_client = request.aws_client_factory.lambda_

response = lambda_client.create_event_source_mapping(**model)
params = copy.deepcopy(model)
if tags := params.get("Tags"):
transformed_tags = {}
for tag_definition in tags:
transformed_tags[tag_definition["Key"]] = tag_definition["Value"]
params["Tags"] = transformed_tags

response = lambda_client.create_event_source_mapping(**params)
model["Id"] = response["UUID"]
model["EventSourceMappingArn"] = response["EventSourceMappingArn"]

return ProgressEvent(
status=OperationStatus.SUCCESS,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import json
import os

import pytest

from localstack.testing.pytest import markers
from localstack.testing.scenario.provisioning import cleanup_s3_bucket
from localstack.utils.strings import short_uid
from localstack.utils.sync import retry
from tests.aws.services.lambda_.event_source_mapping.utils import is_old_esm


@markers.aws.validated
@pytest.mark.skipif(condition=is_old_esm(), reason="Not implemented in v1 provider")
@markers.snapshot.skip_snapshot_verify(
paths=[
"$..Tags.'aws:cloudformation:logical-id'",
"$..Tags.'aws:cloudformation:stack-id'",
"$..Tags.'aws:cloudformation:stack-name'",
]
)
def test_adding_tags(deploy_cfn_template, aws_client, snapshot, cleanups):
template_path = os.path.join(
os.path.join(os.path.dirname(__file__), "../../../templates/event_source_mapping_tags.yml")
)
assert os.path.isfile(template_path)

output_key = f"key-{short_uid()}"
stack = deploy_cfn_template(
template_path=template_path,
parameters={"OutputKey": output_key},
)
# ensure the S3 bucket is empty so we can delete it
cleanups.append(lambda: cleanup_s3_bucket(aws_client.s3, stack.outputs["OutputBucketName"]))

snapshot.add_transformer(snapshot.transform.regex(stack.stack_id, "<stack-id>"))
snapshot.add_transformer(snapshot.transform.regex(stack.stack_name, "<stack-name>"))

event_source_mapping_arn = stack.outputs["EventSourceMappingArn"]
tags_response = aws_client.lambda_.list_tags(Resource=event_source_mapping_arn)
snapshot.match("event-source-mapping-tags", tags_response)

# check the mapping works
queue_url = stack.outputs["QueueUrl"]
aws_client.sqs.send_message(
QueueUrl=queue_url,
MessageBody=json.dumps({"body": "something"}),
)

retry(
lambda: aws_client.s3.head_object(Bucket=stack.outputs["OutputBucketName"], Key=output_key),
retries=10,
sleep=5.0,
)
Comment on lines +43 to +54
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe overkill for this case where we technically only care about CRUD functionality

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but I always like to test the resources created actually work.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.py::test_adding_tags": {
"recorded-date": "06-11-2024, 11:55:29",
"recorded-content": {
"event-source-mapping-tags": {
"Tags": {
"aws:cloudformation:logical-id": "EventSourceMapping",
"aws:cloudformation:stack-id": "<stack-id>",
"aws:cloudformation:stack-name": "<stack-name>",
"my": "tag"
},
"ResponseMetadata": {
"HTTPHeaders": {},
"HTTPStatusCode": 200
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.py::test_adding_tags": {
"last_validated_date": "2024-11-06T11:55:29+00:00"
}
}
120 changes: 120 additions & 0 deletions tests/aws/templates/event_source_mapping_tags.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
Parameters:
OutputKey:
Type: String

Resources:
Queue:
Type: AWS::SQS::Queue
UpdateReplacePolicy: Delete
DeletionPolicy: Delete

FunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: '2012-10-17'
ManagedPolicyArns:
- Fn::Join:
- ''
- - 'arn:'
- Ref: AWS::Partition
- :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Tags:
- Key: my
Value: tag

FunctionRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyDocument:
Statement:
- Action:
- sqs:ChangeMessageVisibility
- sqs:DeleteMessage
- sqs:GetQueueAttributes
- sqs:GetQueueUrl
- sqs:ReceiveMessage
Effect: Allow
Resource:
Fn::GetAtt:
- Queue
- Arn
- Action:
- s3:PutObject
Effect: Allow
Resource:
Fn::Sub:
- "${bucketArn}/${key}"
- bucketArn: !GetAtt OutputBucket.Arn
key: !Ref OutputKey
Version: '2012-10-17'
PolicyName: FunctionRolePolicy
Roles:
- Ref: FunctionRole

OutputBucket:
Type: AWS::S3::Bucket

Function:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |
import os
import boto3

BUCKET = os.environ["BUCKET"]
KEY = os.environ["KEY"]

def handler(event, context):
client = boto3.client("s3")
client.put_object(Bucket=BUCKET, Key=KEY, Body=b"ok")
return "ok"
Handler: index.handler
Environment:
Variables:
BUCKET: !Ref OutputBucket
KEY: !Ref OutputKey

Role:
Fn::GetAtt:
- FunctionRole
- Arn
Runtime: python3.11
Tags:
- Key: my
Value: tag
DependsOn:
- FunctionRolePolicy
- FunctionRole

EventSourceMappi 2364 ng:
Type: AWS::Lambda::EventSourceMapping
Properties:
EventSourceArn:
Fn::GetAtt:
- Queue
- Arn
FunctionName:
Ref: Function
Tags:
- Key: my
Value: tag

Outputs:
QueueUrl:
Value: !Ref Queue

EventSourceMappingArn:
Value: !GetAtt EventSourceMapping.EventSourceMappingArn

FunctionName:
Value: !Ref Function

OutputBucketName:
Value: !Ref OutputBucket
Loading
0