Skip to content

Commit aa657e9

Browse files
authored
fix: Truncate Event Bridge Rule if Id is over 64 characters (#2967)
1 parent 236fdc8 commit aa657e9

File tree

7 files changed

+968
-6
lines changed

7 files changed

+968
-6
lines changed

samtranslator/model/events.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
from typing import Any, Dict, List, Optional
2+
13
from samtranslator.model import GeneratedProperty, Resource
24
from samtranslator.model.intrinsics import fnGetAtt, ref
35

6+
# Event Rule Targets Id and Logical Id has maximum 64 characters limit
7+
# https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_Target.html
8+
EVENT_RULE_LOGICAL_ID_MAX_LENGTH = 64
9+
EVENT_RULE_LOGICAL_ID_EVENT_SUFFIX = "Event"
10+
411

512
class EventsRule(Resource):
613
resource_type = "AWS::Events::Rule"
@@ -16,3 +23,33 @@ class EventsRule(Resource):
1623
}
1724

1825
runtime_attrs = {"rule_id": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn")}
26+
27+
def __init__(
28+
self,
29+
logical_id: Optional[Any],
30+
relative_id: Optional[str] = None,
31+
depends_on: Optional[List[str]] = None,
32+
attributes: Optional[Dict[str, Any]] = None,
33+
) -> None:
34+
super().__init__(logical_id, relative_id, depends_on, attributes)
35+
36+
if len(self.logical_id) > EVENT_RULE_LOGICAL_ID_MAX_LENGTH:
37+
# Truncate logical id to satisfy the EVENT_RULE_ID_MAX_LENGTH limit
38+
self.logical_id = _truncate_with_suffix(
39+
self.logical_id, EVENT_RULE_LOGICAL_ID_MAX_LENGTH, EVENT_RULE_LOGICAL_ID_EVENT_SUFFIX
40+
)
41+
42+
43+
def generate_valid_target_id(logical_id: str, suffix: str) -> str:
44+
"""Truncate Target Id if it is exceeding EVENT_RULE_ID_MAX_LENGTH limi."""
45+
if len(logical_id) + len(suffix) <= EVENT_RULE_LOGICAL_ID_MAX_LENGTH:
46+
return logical_id + suffix
47+
48+
return _truncate_with_suffix(logical_id, EVENT_RULE_LOGICAL_ID_MAX_LENGTH, suffix)
49+
50+
51+
def _truncate_with_suffix(s: str, length: int, suffix: str) -> str:
52+
"""
53+
Truncate string if input string + suffix exceeds length requirement
54+
"""
55+
return s[: length - len(suffix)] + suffix

samtranslator/model/eventsources/push.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from samtranslator.model import PropertyType, ResourceMacro
99
from samtranslator.model.cognito import CognitoUserPool
1010
from samtranslator.model.eventbridge_utils import EventBridgeRuleUtils
11-
from samtranslator.model.events import EventsRule
11+
from samtranslator.model.events import EventsRule, generate_valid_target_id
1212
from samtranslator.model.eventsources import FUNCTION_EVETSOURCE_METRIC_PREFIX
1313
from samtranslator.model.eventsources.pull import SQS
1414
from samtranslator.model.exceptions import InvalidDocumentException, InvalidEventException, InvalidResourceException
@@ -31,6 +31,7 @@
3131
CONDITION = "Condition"
3232

3333
REQUEST_PARAMETER_PROPERTIES = ["Required", "Caching"]
34+
EVENT_RULE_LAMBDA_TARGET_SUFFIX = "LambdaTarget"
3435

3536

3637
class PushEventSource(ResourceMacro, metaclass=ABCMeta):
@@ -176,7 +177,8 @@ def _construct_target(self, function, dead_letter_queue_arn=None): # type: igno
176177
:returns: the Target property
177178
:rtype: dict
178179
"""
179-
target = {"Arn": function.get_runtime_attr("arn"), "Id": self.logical_id + "LambdaTarget"}
180+
target_id = generate_valid_target_id(self.logical_id, EVENT_RULE_LAMBDA_TARGET_SUFFIX)
181+
target = {"Arn": function.get_runtime_attr("arn"), "Id": target_id}
180182
if self.Input is not None:
181183
target["Input"] = self.Input
182184

@@ -271,7 +273,11 @@ def _construct_target(self, function, dead_letter_queue_arn=None): # type: igno
271273
:returns: the Target property
272274
:rtype: dict
273275
"""
274-
target_id = self.Target["Id"] if self.Target and "Id" in self.Target else self.logical_id + "LambdaTarget"
276+
target_id = (
277+
self.Target["Id"]
278+
if self.Target and "Id" in self.Target
279+
else generate_valid_target_id(self.logical_id, EVENT_RULE_LAMBDA_TARGET_SUFFIX)
280+
)
275281
target = {"Arn": function.get_runtime_attr("arn"), "Id": target_id}
276282
if self.Input is not None:
277283
target["Input"] = self.Input

samtranslator/model/stepfunctions/events.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from samtranslator.metrics.method_decorator import cw_timer
66
from samtranslator.model import Property, PropertyType, Resource, ResourceMacro
77
from samtranslator.model.eventbridge_utils import EventBridgeRuleUtils
8-
from samtranslator.model.events import EventsRule
8+
from samtranslator.model.events import EventsRule, generate_valid_target_id
99
from samtranslator.model.eventsources.push import Api as PushApi
1010
from samtranslator.model.exceptions import InvalidEventException
1111
from samtranslator.model.iam import IAMRole, IAMRolePolicies
@@ -16,6 +16,7 @@
1616

1717
CONDITION = "Condition"
1818
SFN_EVETSOURCE_METRIC_PREFIX = "SFNEventSource"
19+
EVENT_RULE_SFN_TARGET_SUFFIX = "StepFunctionsTarget"
1920

2021

2122
class EventSource(ResourceMacro, metaclass=ABCMeta):
@@ -156,7 +157,9 @@ def _construct_target(self, resource, role, dead_letter_queue_arn=None): # type
156157
:rtype: dict
157158
"""
158159
target_id = (
159-
self.Target["Id"] if self.Target and "Id" in self.Target else self.logical_id + "StepFunctionsTarget"
160+
self.Target["Id"]
161+
if self.Target and "Id" in self.Target
162+
else generate_valid_target_id(self.logical_id, EVENT_RULE_SFN_TARGET_SUFFIX)
160163
)
161164
target = {
162165
"Arn": resource.get_runtime_attr("arn"),
@@ -249,7 +252,9 @@ def _construct_target(self, resource, role, dead_letter_queue_arn=None): # type
249252
:rtype: dict
250253
"""
251254
target_id = (
252-
self.Target["Id"] if self.Target and "Id" in self.Target else self.logical_id + "StepFunctionsTarget"
255+
self.Target["Id"]
256+
if self.Target and "Id" in self.Target
257+
else generate_valid_target_id(self.logical_id, EVENT_RULE_SFN_TARGET_SUFFIX)
253258
)
254259
target = {
255260
"Arn": resource.get_runtime_attr("arn"),
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
Transform: AWS::Serverless-2016-10-31
2+
3+
Resources:
4+
QueryForAvailabilityWithUserExceptionQueryForAvailabilityWithUserException:
5+
Type: AWS::Serverless::Function
6+
Properties:
7+
Handler: index.handler
8+
Runtime: nodejs14.x
9+
InlineCode: |
10+
exports.handler = async (event, context, callback) => {
11+
return {
12+
statusCode: 200,
13+
body: 'Success'
14+
}
15+
}
16+
Events:
17+
QueryForAvailabilityWithUserExceptionEvent:
18+
Type: Schedule
19+
Properties:
20+
Schedule: cron(05 12 * * ? *)
21+
22+
SuperSuperSuperSuperLongNameForStepFunction:
23+
Type: AWS::Serverless::StateMachine
24+
Properties:
25+
Name: MyStateMachine
26+
Events:
27+
SuperSuperSuperSuperLongNameForStepFunctionCWEventEvent:
28+
Type: CloudWatchEvent
29+
Properties:
30+
Pattern:
31+
detail:
32+
state:
33+
- terminated
34+
MyApiEvent:
35+
Type: Api
36+
Properties:
37+
Path: /startMyExecution
38+
Method: post
39+
DefinitionUri:
40+
Bucket: sam-demo-bucket
41+
Key: my-state-machine.asl.json
42+
Version: 3
43+
Role: !Sub 'arn:${AWS::Partition}:iam::123456123456:role/service-role/SampleRole'

0 commit comments

Comments
 (0)