Repository: Miserlou/Zappa

Issue:
Too long scheduled event names result in errors updating and/or duplicate events
## Context
There seems to be a 64 char limit to schedule event names. If the combination of the project name plus stage name plus event function exceed 64 chars, the logic that creates the name differs from the logic that unschedules the event.

This results in an error updating - the event will fail to create with a LimitExceededException: An error occurred (LimitExceededException) when calling the PutTargets operation: The requested resource exceeds the maximum number allowed.

## Expected Behavior
Events should be removed and recreated when updating.

## Actual Behavior
The event isn't deleted and the update fails

## Possible Fix
Looks like the issue is related to zappa.py:

```
    def get_event_name(lambda_name, name):
        """
        Returns an AWS-valid Lambda event name.

        """
        return '{prefix:.{width}}-{postfix}'.format(prefix=lambda_name, width=max(0, 63 - len(name)), postfix=name)[:64]
```

If the name is too long, the prefix gets truncated.

`zappa.unschedule_events` - lists events using the lambda_name prefix (the project name plus '-' plus stage name. `self.events_client.list_rules(NamePrefix=lambda_name)` - however the name doesn't always have that prefix due the way they are created.

## Steps to Reproduce
1. Create a project - `'bugproject'`
2. Configure a scheduled event with name -` 'modulename.realllllllyyyyyylongmethodnameeeeee'`
3. Deploy to a stage - `'stagename'`
4. Note that `zappa.get_event_name` will generate `'bugproject-stagen-modulename.realllllllyyyyyylongmethodnameeeeee'` as the name
5. Update the stage. Observe error because `zappa.unschedule_events` assumes the prefix will be `bugproject.stagename`, but it is actually `bugproject-stagen`.


## Context
Resulted in inability to update.

## Your Environment




Discussion:

Resolving patch:
diff --git a/zappa/cli.py b/zappa/cli.py
--- a/zappa/cli.py
+++ b/zappa/cli.py
@@ -985,8 +985,9 @@ def tabular_print(title, value):
         status_dict["Lambda Versions"] = len(lambda_versions)
         function_response = self.zappa.lambda_client.get_function(FunctionName=self.lambda_name)
         conf = function_response['Configuration']
+        self.lambda_arn = conf['FunctionArn']
         status_dict["Lambda Name"] = self.lambda_name
-        status_dict["Lambda ARN"] = conf['FunctionArn']
+        status_dict["Lambda ARN"] = self.lambda_arn
         status_dict["Lambda Role ARN"] = conf['Role']
         status_dict["Lambda Handler"] = conf['Handler']
         status_dict["Lambda Code Size"] = conf['CodeSize']
@@ -1058,7 +1059,7 @@ def tabular_print(title, value):
                 status_dict["Domain URL"] = "None Supplied"
 
         # Scheduled Events
-        event_rules = self.zappa.get_event_rules_for_lambda(lambda_name=self.lambda_name)
+        event_rules = self.zappa.get_event_rules_for_lambda(lambda_arn=self.lambda_arn)
         status_dict["Num. Event Rules"] = len(event_rules)
         if len(event_rules) > 0:
             status_dict['Events'] = []
diff --git a/zappa/zappa.py b/zappa/zappa.py
--- a/zappa/zappa.py
+++ b/zappa/zappa.py
@@ -1840,12 +1840,25 @@ def delete_rule(self, rule_name):
         # Delete our rule.
         self.events_client.delete_rule(Name=rule_name)
 
-    def get_event_rules_for_lambda(self, lambda_name):
+    def get_event_rule_names_for_lambda(self, lambda_arn):
         """
-        Get all of the rules associated with this function.
+        Get all of the rule names associated with a lambda function.
         """
-        rules = [r['Name'] for r in self.events_client.list_rules(NamePrefix=lambda_name)['Rules']]
-        return [self.events_client.describe_rule(Name=r) for r in rules]
+        response = self.events_client.list_rule_names_by_target(TargetArn=lambda_arn)
+        rule_names = response['RuleNames']
+        # Iterate when the results are paginated
+        while 'NextToken' in response:
+            response = self.events_client.list_rule_names_by_target(TargetArn=lambda_arn,
+                                                                    NextToken=response['NextToken'])
+            rule_names.extend(response['RuleNames'])
+        return rule_names
+
+    def get_event_rules_for_lambda(self, lambda_arn):
+        """
+        Get all of the rule details associated with this function.
+        """
+        rule_names = self.get_event_rule_names_for_lambda(lambda_arn=lambda_arn)
+        return [self.events_client.describe_rule(Name=r) for r in rule_names]
 
     def unschedule_events(self, events, lambda_arn=None, lambda_name=None, excluded_source_services=None):
         excluded_source_services = excluded_source_services or []
@@ -1857,9 +1870,8 @@ def unschedule_events(self, events, lambda_arn=None, lambda_name=None, excluded_
         """
         self._clear_policy(lambda_name)
 
-        rules = self.events_client.list_rules(NamePrefix=lambda_name)
-        for rule in rules['Rules']:
-            rule_name = rule['Name']
+        rule_names = self.get_event_rule_names_for_lambda(lambda_arn=lambda_arn)
+        for rule_name in rule_names:
             self.delete_rule(rule_name)
             print('Unscheduled ' + rule_name + '.')
 


Test patch:
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_1.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_1.json
new file mode 100644
--- /dev/null
+++ b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_1.json
@@ -0,0 +1,12 @@
+{
+    "status_code": 200,
+    "data": {
+        "RuleNames": [
+            "zappa-keep-warm-zappa-ttt666"
+        ],
+        "ResponseMetadata": {
+            "HTTPStatusCode": 200,
+            "RequestId": "afe859ba-28f4-11e6-aa28-4d9f2eb25de5"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_2.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_2.json
new file mode 100644
--- /dev/null
+++ b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_2.json
@@ -0,0 +1,12 @@
+{
+    "status_code": 200,
+    "data": {
+        "RuleNames": [
+            "zappa-keep-warm-zappa-ttt888"
+        ],
+        "ResponseMetadata": {
+            "HTTPStatusCode": 200,
+            "RequestId": "afe859ba-28f4-11e6-aa28-4d9f2eb25de5"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_3.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_3.json
new file mode 100644
--- /dev/null
+++ b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_3.json
@@ -0,0 +1,12 @@
+{
+    "status_code": 200,
+    "data": {
+        "RuleNames": [
+            "zappa-keep-warm-zappa-ttt888"
+        ],
+        "ResponseMetadata": {
+            "HTTPStatusCode": 200,
+            "RequestId": "afe859ba-28f4-11e6-aa28-4d9f2eb25de5"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_4.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_4.json
new file mode 100644
--- /dev/null
+++ b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_4.json
@@ -0,0 +1,10 @@
+{
+    "status_code": 200,
+    "data": {
+        "RuleNames": [],
+        "ResponseMetadata": {
+            "HTTPStatusCode": 200,
+            "RequestId": "afe859ba-28f4-11e6-aa28-4d9f2eb25de5"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_5.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_5.json
new file mode 100644
--- /dev/null
+++ b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_5.json
@@ -0,0 +1,13 @@
+{
+    "status_code": 200,
+    "data": {
+        "RuleNames": [
+            "zappa-ttt888-tests.test_app.schedule_me",
+            "zappa-ttt888-zappa-keep-warm-handler.keep_warm_callback"
+        ],
+        "ResponseMetadata": {
+            "HTTPStatusCode": 200,
+            "RequestId": "afe859ba-28f4-11e6-aa28-4d9f2eb25de5"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_6.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_6.json
new file mode 100644
--- /dev/null
+++ b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_6.json
@@ -0,0 +1,13 @@
+{
+    "status_code": 200,
+    "data": {
+        "RuleNames": [
+            "zappa-ttt888-tests.test_app.schedule_me",
+            "zappa-ttt888-zappa-keep-warm-handler.keep_warm_callback"
+        ],
+        "ResponseMetadata": {
+            "HTTPStatusCode": 200,
+            "RequestId": "afe859ba-28f4-11e6-aa28-4d9f2eb25de5"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_7.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_7.json
new file mode 100644
--- /dev/null
+++ b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_7.json
@@ -0,0 +1,13 @@
+{
+    "status_code": 200,
+    "data": {
+        "RuleNames": [
+            "zappa-ttt888-tests.test_app.schedule_me",
+            "zappa-ttt888-zappa-keep-warm-handler.keep_warm_callback"
+        ],
+        "ResponseMetadata": {
+            "HTTPStatusCode": 200,
+            "RequestId": "afe859ba-28f4-11e6-aa28-4d9f2eb25de5"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_8.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_8.json
new file mode 100644
--- /dev/null
+++ b/tests/placebo/TestZappa.test_cli_aws/events.ListRuleNamesByTarget_8.json
@@ -0,0 +1,10 @@
+{
+    "status_code": 200,
+    "data": {
+        "RuleNames": [],
+        "ResponseMetadata": {
+            "HTTPStatusCode": 200,
+            "RequestId": "afe859ba-28f4-11e6-aa28-4d9f2eb25de5"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_1.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRules_1.json
deleted file mode 100644
--- a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_1.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "status_code": 200, 
-    "data": {
-        "Rules": [
-            {
-                "ScheduleExpression": "rate(5 minutes)", 
-                "Name": "zappa-keep-warm-zappa-ttt666", 
-                "RoleArn": "arn:aws:iam::724336686645:role/ZappaLambdaExecution", 
-                "State": "ENABLED", 
-                "Arn": "arn:aws:events:us-east-1:724336686645:rule/zappa-keep-warm-zappa-ttt666", 
-                "Description": "Zappa Keep Warm - zappa-ttt666"
-            }
-        ], 
-        "ResponseMetadata": {
-            "HTTPStatusCode": 200, 
-            "RequestId": "afe859ba-28f4-11e6-aa28-4d9f2eb25de5"
-        }
-    }
-}
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_2.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRules_2.json
deleted file mode 100644
--- a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_2.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "status_code": 200, 
-    "data": {
-        "Rules": [
-            {
-                "ScheduleExpression": "rate(5 minutes)", 
-                "Name": "zappa-keep-warm-zappa-ttt888", 
-                "RoleArn": "arn:aws:iam::724336686645:role/ZappaLambdaExecution", 
-                "State": "ENABLED", 
-                "Arn": "arn:aws:events:us-east-1:724336686645:rule/zappa-keep-warm-zappa-ttt888", 
-                "Description": "Zappa Keep Warm - zappa-ttt888"
-            }
-        ], 
-        "ResponseMetadata": {
-            "HTTPStatusCode": 200, 
-            "RequestId": "a38b5763-28f7-11e6-a108-6908dca1b4ef"
-        }
-    }
-}
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_3.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRules_3.json
deleted file mode 100644
--- a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_3.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "status_code": 200, 
-    "data": {
-        "Rules": [
-            {
-                "ScheduleExpression": "rate(5 minutes)", 
-                "Name": "zappa-keep-warm-zappa-ttt888", 
-                "RoleArn": "arn:aws:iam::724336686645:role/ZappaLambdaExecution", 
-                "State": "ENABLED", 
-                "Arn": "arn:aws:events:us-east-1:724336686645:rule/zappa-keep-warm-zappa-ttt888", 
-                "Description": "Zappa Keep Warm - zappa-ttt888"
-            }
-        ], 
-        "ResponseMetadata": {
-            "HTTPStatusCode": 200, 
-            "RequestId": "b0f57c27-28f7-11e6-8e21-7d2bd33e0450"
-        }
-    }
-}
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_4.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRules_4.json
deleted file mode 100644
--- a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_4.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-    "status_code": 200, 
-    "data": {
-        "Rules": [], 
-        "ResponseMetadata": {
-            "HTTPStatusCode": 200, 
-            "RequestId": "2b5f3901-6a74-11e6-945c-0b1ddee71d5d", 
-            "HTTPHeaders": {
-                "x-amzn-requestid": "2b5f3901-6a74-11e6-945c-0b1ddee71d5d", 
-                "date": "Thu, 25 Aug 2016 03:29:45 GMT", 
-                "content-length": "12", 
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
-    }
-}
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_5.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRules_5.json
deleted file mode 100644
--- a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_5.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "status_code": 200, 
-    "data": {
-        "Rules": [
-            {
-                "ScheduleExpression": "rate(1 minute)", 
-                "Name": "zappa-ttt888-tests.test_app.schedule_me", 
-                "RoleArn": "arn:aws:iam::724336686645:role/ZappaLambdaExecution", 
-                "State": "ENABLED", 
-                "Arn": "arn:aws:events:us-east-1:724336686645:rule/zappa-ttt888-tests.test_app.schedule_me", 
-                "Description": "tests.test_app.schedule_me"
-            }, 
-            {
-                "ScheduleExpression": "rate(4 minutes)", 
-                "Name": "zappa-ttt888-zappa-keep-warm-handler.keep_warm_callback", 
-                "RoleArn": "arn:aws:iam::724336686645:role/ZappaLambdaExecution", 
-                "State": "ENABLED", 
-                "Arn": "arn:aws:events:us-east-1:724336686645:rule/zappa-ttt888-zappa-keep-warm-handler.keep_warm_callback", 
-                "Description": "Zappa Keep Warm - zappa-ttt888"
-            }
-        ], 
-        "ResponseMetadata": {
-            "HTTPStatusCode": 200, 
-            "RequestId": "665efadb-6a74-11e6-b1df-6905c3c8daa6", 
-            "HTTPHeaders": {
-                "x-amzn-requestid": "665efadb-6a74-11e6-b1df-6905c3c8daa6", 
-                "date": "Thu, 25 Aug 2016 03:31:24 GMT", 
-                "content-length": "658", 
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
-    }
-}
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_6.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRules_6.json
deleted file mode 100644
--- a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_6.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "status_code": 200, 
-    "data": {
-        "Rules": [
-            {
-                "ScheduleExpression": "rate(1 minute)", 
-                "Name": "zappa-ttt888-tests.test_app.schedule_me", 
-                "RoleArn": "arn:aws:iam::724336686645:role/ZappaLambdaExecution", 
-                "State": "ENABLED", 
-                "Arn": "arn:aws:events:us-east-1:724336686645:rule/zappa-ttt888-tests.test_app.schedule_me", 
-                "Description": "tests.test_app.schedule_me"
-            }, 
-            {
-                "ScheduleExpression": "rate(4 minutes)", 
-                "Name": "zappa-ttt888-zappa-keep-warm-handler.keep_warm_callback", 
-                "RoleArn": "arn:aws:iam::724336686645:role/ZappaLambdaExecution", 
-                "State": "ENABLED", 
-                "Arn": "arn:aws:events:us-east-1:724336686645:rule/zappa-ttt888-zappa-keep-warm-handler.keep_warm_callback", 
-                "Description": "Zappa Keep Warm - zappa-ttt888"
-            }
-        ], 
-        "ResponseMetadata": {
-            "HTTPStatusCode": 200, 
-            "RequestId": "a01e26f3-6a74-11e6-a237-bb13171f213e", 
-            "HTTPHeaders": {
-                "x-amzn-requestid": "a01e26f3-6a74-11e6-a237-bb13171f213e", 
-                "date": "Thu, 25 Aug 2016 03:33:01 GMT", 
-                "content-length": "658", 
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
-    }
-}
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_7.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRules_7.json
deleted file mode 100644
--- a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_7.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "status_code": 200, 
-    "data": {
-        "Rules": [
-            {
-                "ScheduleExpression": "rate(1 minute)", 
-                "Name": "zappa-ttt888-tests.test_app.schedule_me", 
-                "RoleArn": "arn:aws:iam::724336686645:role/ZappaLambdaExecution", 
-                "State": "ENABLED", 
-                "Arn": "arn:aws:events:us-east-1:724336686645:rule/zappa-ttt888-tests.test_app.schedule_me", 
-                "Description": "tests.test_app.schedule_me"
-            }, 
-            {
-                "ScheduleExpression": "rate(4 minutes)", 
-                "Name": "zappa-ttt888-zappa-keep-warm-handler.keep_warm_callback", 
-                "RoleArn": "arn:aws:iam::724336686645:role/ZappaLambdaExecution", 
-                "State": "ENABLED", 
-                "Arn": "arn:aws:events:us-east-1:724336686645:rule/zappa-ttt888-zappa-keep-warm-handler.keep_warm_callback", 
-                "Description": "Zappa Keep Warm - zappa-ttt888"
-            }
-        ], 
-        "ResponseMetadata": {
-            "HTTPStatusCode": 200, 
-            "RequestId": "a1a786d2-6a74-11e6-a237-bb13171f213e", 
-            "HTTPHeaders": {
-                "x-amzn-requestid": "a1a786d2-6a74-11e6-a237-bb13171f213e", 
-                "date": "Thu, 25 Aug 2016 03:33:03 GMT", 
-                "content-length": "658", 
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
-    }
-}
diff --git a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_8.json b/tests/placebo/TestZappa.test_cli_aws/events.ListRules_8.json
deleted file mode 100644
--- a/tests/placebo/TestZappa.test_cli_aws/events.ListRules_8.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-    "status_code": 200, 
-    "data": {
-        "Rules": [], 
-        "ResponseMetadata": {
-            "HTTPStatusCode": 200, 
-            "RequestId": "a34ea70f-6a74-11e6-a237-bb13171f213e", 
-            "HTTPHeaders": {
-                "x-amzn-requestid": "a34ea70f-6a74-11e6-a237-bb13171f213e", 
-                "date": "Thu, 25 Aug 2016 03:33:06 GMT", 
-                "content-length": "12", 
-                "content-type": "application/x-amz-json-1.1"
-            }
-        }
-    }
-}