Skip to content
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

Ensure unique scheduled event names #1080

Merged
merged 2 commits into from
Nov 16, 2021
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
83 changes: 71 additions & 12 deletions tests/tests.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf8 -*-
import collections
import hashlib
import json
import os
import random
Expand Down Expand Up @@ -2048,22 +2049,80 @@ def test_event_name(self):
self.assertTrue(len(truncated) <= 64)
self.assertEqual(truncated, "a-b")

def test_hashed_rule_name(self):
def test_get_scheduled_event_name(self):
zappa = Zappa()
truncated = zappa.get_event_name(
"basldfkjalsdkfjalsdkfjaslkdfjalsdkfjadlsfkjasdlfkjasdlfkjasdflkjasdf-asdfasdfasdfasdfasdf",
"this.is.my.dang.function.wassup.yeah.its.long",
event = {}
function = "foo"
lambda_name = "bar"
self.assertEqual(
zappa.get_scheduled_event_name(event, function, lambda_name),
f"{lambda_name}-{function}",
)
self.assertTrue(len(truncated) == 64)

rule_name = 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",
def test_get_scheduled_event_name__has_name(self):
zappa = Zappa()
event = {"name": "my_event"}
function = "foo"
lambda_name = "bar"
self.assertEqual(
zappa.get_scheduled_event_name(event, function, lambda_name),
f"{lambda_name}-{event['name']}-{function}",
)
self.assertTrue(len(rule_name) <= 64)
self.assertTrue(
rule_name.endswith("-this.is.my.dang.function.wassup.yeah.its.long")

def test_get_scheduled_event_name__has_index(self):
zappa = Zappa()
event = {}
function = "foo"
lambda_name = "bar"
index = 1
self.assertEqual(
zappa.get_scheduled_event_name(event, function, lambda_name, index),
f"{lambda_name}-{index}-{function}",
)

def test_get_scheduled_event_name__has_name__has_index(self):
zappa = Zappa()
event = {"name": "my_event"}
function = "foo"
lambda_name = "bar"
index = 1
self.assertEqual(
zappa.get_scheduled_event_name(event, function, lambda_name, index),
f"{lambda_name}-{index}-{event['name']}-{function}",
)

def test_get_scheduled_event_name__truncated(self):
zappa = Zappa()
event = {}
function = "foo"
lambda_name = "bar" * 100
hashed_lambda_name = hashlib.sha1(lambda_name.encode()).hexdigest()
self.assertEqual(
zappa.get_scheduled_event_name(event, function, lambda_name),
f"{hashed_lambda_name}-{function}",
)

def test_get_scheduled_event_name__truncated__has_name(self):
zappa = Zappa()
event = {"name": "my_event"}
function = "foo"
lambda_name = "bar" * 100
hashed_lambda_name = hashlib.sha1(lambda_name.encode()).hexdigest()
self.assertEqual(
zappa.get_scheduled_event_name(event, function, lambda_name),
f"{hashed_lambda_name}-{event['name']}-{function}",
)

def test_get_scheduled_event_name__truncated__has_name__has_index(self):
zappa = Zappa()
event = {"name": "my_event"}
function = "foo"
lambda_name = "bar" * 100
index = 1
hashed_lambda_name = hashlib.sha1(lambda_name.encode()).hexdigest()
self.assertEqual(
zappa.get_scheduled_event_name(event, function, lambda_name, index),
f"{hashed_lambda_name}-{index}-{event['name']}-{function}",
)

def test_detect_dj(self):
Expand Down
45 changes: 21 additions & 24 deletions zappa/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3031,17 +3031,12 @@ def schedule_events(self, lambda_arn, lambda_name, events, default=True):

if expressions:
for index, expression in enumerate(expressions):
name = self.get_scheduled_event_name(
event, function, lambda_name, index
rule_name = self.get_scheduled_event_name(
event,
function,
lambda_name,
index,
)
# 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
)
else:
rule_name = name

rule_response = self.events_client.put_rule(
Name=rule_name,
Expand Down Expand Up @@ -3158,12 +3153,15 @@ def schedule_events(self, lambda_arn, lambda_name, events, default=True):
else:
print(
"Could not create event {} - Please define either an expression or an event source".format(
name
rule_name,
)
)

@staticmethod
def get_scheduled_event_name(event, function, lambda_name, index=0):
def get_scheduled_event_name(self, event, function, lambda_name, index=0):
"""
Returns an AWS-valid CloudWatch rule name using a digest of the event name, lambda name, and function.
This allows support for rule names that may be longer than the 64 char limit.
"""
name = event.get("name", function)
if name != function:
# a custom event name has been provided, make sure function name is included as postfix,
Expand All @@ -3175,7 +3173,14 @@ def get_scheduled_event_name(event, function, lambda_name, index=0):
# Related: https://github.com/Miserlou/Zappa/pull/1051
name = "{}-{}".format(index, name)
# prefix scheduled event names with lambda name. So we can look them up later via the prefix.
return Zappa.get_event_name(lambda_name, name)
event_name = self.get_event_name(lambda_name, name)
# if it's possible that we truncated name, generate a unique, shortened name
# https://github.com/Miserlou/Zappa/issues/970
if len(event_name) >= 64:
lambda_name = self.get_hashed_lambda_name(lambda_name)
event_name = self.get_event_name(lambda_name, name)

return event_name

@staticmethod
def get_event_name(lambda_name, name):
Expand All @@ -3187,16 +3192,8 @@ def get_event_name(lambda_name, name):
)[:64]

@staticmethod
def get_hashed_rule_name(event, function, lambda_name):
"""
Returns an AWS-valid CloudWatch rule name using a digest of the event name, lambda name, and function.
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()
return Zappa.get_event_name(name_hash, function)
def get_hashed_lambda_name(lambda_name):
return hashlib.sha1(lambda_name.encode()).hexdigest()

def delete_rule(self, rule_name):
"""
Expand Down