Skip to content

Commit

Permalink
Unique rule names for multiple CloudWatch expressions (#1727)
Browse files Browse the repository at this point in the history
A mixture of two cases that were handled individually uncovers an
incorrect behavior: when a function has multiple event expressions AND
the resulting rule name would be >= 64 characters long, all expressions
get the same hash, so only the last expression is scheduled.

In this commit, the index of the expression is used to build the hash,
but only if the index is not zero — this is possibly not needed, but
ensures current hashes are preserved.
  • Loading branch information
edudobay committed May 10, 2021
1 parent 9036220 commit 51e6a46
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 8 deletions.
19 changes: 15 additions & 4 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1677,12 +1677,23 @@ def test_hashed_rule_name(self):
"this.is.my.dang.function.wassup.yeah.its.long")
self.assertTrue(len(truncated) == 64)

rule_name = zappa.get_hashed_rule_name(
rule_name_index0 = zappa.get_hashed_rule_name(
event=dict(name='some-event-name'),
function="this.is.my.dang.function.wassup.yeah.its.long",
lambda_name="basldfkjalsdkfjalsdkfjaslkdfjalsdkfjadlsfkjasdlfkjasdlfkjasdflkjasdf-asdfasdfasdfasdfasdf")
self.assertTrue(len(rule_name) <= 64)
self.assertTrue(rule_name.endswith("-this.is.my.dang.function.wassup.yeah.its.long"))
lambda_name="basldfkjalsdkfjalsdkfjaslkdfjalsdkfjadlsfkjasdlfkjasdlfkjasdflkjasdf-asdfasdfasdfasdfasdf",
index=0)
self.assertTrue(len(rule_name_index0) <= 64)
self.assertTrue(rule_name_index0.endswith("-this.is.my.dang.function.wassup.yeah.its.long"))

rule_name_index1 = zappa.get_hashed_rule_name(
event=dict(name='some-event-name'),
function="this.is.my.dang.function.wassup.yeah.its.long",
lambda_name="basldfkjalsdkfjalsdkfjaslkdfjalsdkfjadlsfkjasdlfkjasdlfkjasdflkjasdf-asdfasdfasdfasdfasdf",
index=1)
self.assertTrue(len(rule_name_index1) <= 64)
self.assertTrue(rule_name_index1.endswith("-this.is.my.dang.function.wassup.yeah.its.long"))

self.assertNotEqual(rule_name_index0, rule_name_index1)

def test_detect_dj(self):
# Sanity
Expand Down
17 changes: 13 additions & 4 deletions zappa/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2687,7 +2687,7 @@ def schedule_events(self, lambda_arn, lambda_name, events, default=True):
# if it's possible that we truncated name, generate a unique, shortened name
# https://github.com/Miserlou/Zappa/issues/970
if len(name) >= 64:
rule_name = self.get_hashed_rule_name(event, function, lambda_name)
rule_name = self.get_hashed_rule_name(event, function, lambda_name, index)
else:
rule_name = name

Expand Down Expand Up @@ -2805,13 +2805,22 @@ def get_event_name(lambda_name, name):
return '{prefix:.{width}}-{postfix}'.format(prefix=lambda_name, width=max(0, 63 - len(name)), postfix=name)[:64]

@staticmethod
def get_hashed_rule_name(event, function, lambda_name):
def get_hashed_rule_name(event, function, lambda_name, index=0):
"""
Returns an AWS-valid CloudWatch rule name using a digest of the event name, lambda name, and function.
Returns an AWS-valid CloudWatch rule name using a digest of the event name, lambda name, function,
and an index in the case of multiple scheduling expressions.
This allows support for rule names that may be longer than the 64 char limit.
"""
event_name = event.get('name', function)
name_hash = hashlib.sha1('{}-{}'.format(lambda_name, event_name).encode('UTF-8')).hexdigest()
name = '{}-{}'.format(lambda_name, event_name)

# Similarly to get_scheduled_event_name, we need unique rule names in case of multiple expressions.
# Related: https://github.com/Miserlou/Zappa/issues/1727
if index:
name = '{}-{}'.format(name, index)

name_hash = hashlib.sha1(name.encode('UTF-8')).hexdigest()
return Zappa.get_event_name(name_hash, function)

def delete_rule(self, rule_name):
Expand Down

0 comments on commit 51e6a46

Please sign in to comment.