We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Kinesis putRecords error
It seems that putRecords causes the following error:

```
Starting mock Kinesis (http port 4568)...
Starting mock S3 (http port 4572)...
Starting mock Firehose service (http port 4573)...
Starting mock Lambda service (http port 4574)...
Listening at http://:::4565
* Running on http://0.0.0.0:4563/ (Press CTRL+C to quit)
127.0.0.1 - - [08/May/2018 13:52:25] "GET / HTTP/1.1" 200 -
Ready.
r127.0.0.1 - - [08/May/2018 13:56:43] "PUT /prd1541-qa1-vf-sms-send-stream-archive HTTP/1.1" 200 -
127.0.0.1 - - [08/May/2018 13:56:43] "HEAD /prd1541-qa1-vf-sms-send-stream-archive HTTP/1.1" 200 -
2018-05-08T13:56:43:ERROR:localstack.services.generic_proxy: Error forwarding request: 'Records' Traceback (most recent call last):
  File "/opt/code/localstack/localstack/services/generic_proxy.py", line 215, in forward
    updated_response = self.proxy.update_listener.return_response(**kwargs)
  File "/opt/code/localstack/localstack/services/kinesis/kinesis_listener.py", line 49, in return_response
    response_records = response_body['Records']
KeyError: 'Records'

2018-05-08T13:56:43:ERROR:localstack.services.generic_proxy: Error forwarding request: 'Records' Traceback (most recent call last):
  File "/opt/code/localstack/localstack/services/generic_proxy.py", line 215, in forward
    updated_response = self.proxy.update_listener.return_response(**kwargs)
  File "/opt/code/localstack/localstack/services/kinesis/kinesis_listener.py", line 49, in return_response
    response_records = response_body['Records']
KeyError: 'Records'

2018-05-08T13:56:43:ERROR:localstack.services.generic_proxy: Error forwarding request: 'Records' Traceback (most recent call last):
  File "/opt/code/localstack/localstack/services/generic_proxy.py", line 215, in forward
    updated_response = self.proxy.update_listener.return_response(**kwargs)
  File "/opt/code/localstack/localstack/services/kinesis/kinesis_listener.py", line 49, in return_response
    response_records = response_body['Records']
KeyError: 'Records'
```

I'm using the latest localstack image and my `Kinesis.putRecords` call goes through the Javascript AWS SDK: 

```
...
  const result = await client.putRecords({
    StreamName,
    Records: records.map(data => ({
      Data: new Buffer(JSON.stringify(data)),
      PartitionKey: 'testPartition'
    }))
  }).promise();
...
```

It seems like there's a mismatch int the expected format in `kinesis_listener.py`.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `localstack/services/kinesis/kinesis_listener.py`
Content:
```
1 import json
2 import random
3 from requests.models import Response
4 from localstack import config
5 from localstack.utils.common import to_str
6 from localstack.utils.analytics import event_publisher
7 from localstack.services.awslambda import lambda_api
8 from localstack.services.generic_proxy import ProxyListener
9 
10 # action headers
11 ACTION_PREFIX = 'Kinesis_20131202'
12 ACTION_PUT_RECORD = '%s.PutRecord' % ACTION_PREFIX
13 ACTION_PUT_RECORDS = '%s.PutRecords' % ACTION_PREFIX
14 ACTION_CREATE_STREAM = '%s.CreateStream' % ACTION_PREFIX
15 ACTION_DELETE_STREAM = '%s.DeleteStream' % ACTION_PREFIX
16 ACTION_UPDATE_SHARD_COUNT = '%s.UpdateShardCount' % ACTION_PREFIX
17 
18 
19 class ProxyListenerKinesis(ProxyListener):
20 
21     def forward_request(self, method, path, data, headers):
22         data = json.loads(to_str(data))
23         action = headers.get('X-Amz-Target')
24 
25         if action == '%s.DescribeStreamSummary' % ACTION_PREFIX:
26             stream_arn = data.get('StreamARN') or data['StreamName']
27             # TODO fix values below
28             result = {
29                 'StreamDescriptionSummary': {
30                     'ConsumerCount': 0,
31                     'EnhancedMonitoring': [],
32                     'KeyId': 'string',
33                     'OpenShardCount': 0,
34                     'RetentionPeriodHours': 1,
35                     'StreamARN': stream_arn,
36                     # 'StreamCreationTimestamp': number,
37                     'StreamName': data['StreamName'],
38                     'StreamStatus': 'ACTIVE'
39                 }
40             }
41             return result
42         if action == '%s.DescribeStreamConsumer' % ACTION_PREFIX:
43             consumer_arn = data.get('ConsumerARN') or data['ConsumerName']
44             consumer_name = data.get('ConsumerName') or data['ConsumerARN']
45             result = {
46                 'ConsumerDescription': {
47                     'ConsumerARN': consumer_arn,
48                     # 'ConsumerCreationTimestamp': number,
49                     'ConsumerName': consumer_name,
50                     'ConsumerStatus': 'ACTIVE',
51                     'StreamARN': data.get('StreamARN')
52                 }
53             }
54             return result
55 
56         if random.random() < config.KINESIS_ERROR_PROBABILITY:
57             action = headers.get('X-Amz-Target')
58             if action in [ACTION_PUT_RECORD, ACTION_PUT_RECORDS]:
59                 return kinesis_error_response(data, action)
60         return True
61 
62     def return_response(self, method, path, data, headers, response):
63         action = headers.get('X-Amz-Target')
64         data = json.loads(to_str(data))
65 
66         records = []
67         if action in (ACTION_CREATE_STREAM, ACTION_DELETE_STREAM):
68             event_type = (event_publisher.EVENT_KINESIS_CREATE_STREAM if action == ACTION_CREATE_STREAM
69                           else event_publisher.EVENT_KINESIS_DELETE_STREAM)
70             payload = {'n': event_publisher.get_hash(data.get('StreamName'))}
71             if action == ACTION_CREATE_STREAM:
72                 payload['s'] = data.get('ShardCount')
73             event_publisher.fire_event(event_type, payload=payload)
74         elif action == ACTION_PUT_RECORD:
75             response_body = json.loads(to_str(response.content))
76             event_record = {
77                 'data': data['Data'],
78                 'partitionKey': data['PartitionKey'],
79                 'sequenceNumber': response_body.get('SequenceNumber')
80             }
81             event_records = [event_record]
82             stream_name = data['StreamName']
83             lambda_api.process_kinesis_records(event_records, stream_name)
84         elif action == ACTION_PUT_RECORDS:
85             event_records = []
86             response_body = json.loads(to_str(response.content))
87             response_records = response_body['Records']
88             records = data['Records']
89             for index in range(0, len(records)):
90                 record = records[index]
91                 event_record = {
92                     'data': record['Data'],
93                     'partitionKey': record['PartitionKey'],
94                     'sequenceNumber': response_records[index].get('SequenceNumber')
95                 }
96                 event_records.append(event_record)
97             stream_name = data['StreamName']
98             lambda_api.process_kinesis_records(event_records, stream_name)
99         elif action == ACTION_UPDATE_SHARD_COUNT:
100             # Currently kinesalite, which backs the Kinesis implementation for localstack, does
101             # not support UpdateShardCount:
102             # https://github.com/mhart/kinesalite/issues/61
103             #
104             # [Terraform](https://www.terraform.io) makes the call to UpdateShardCount when it
105             # applies Kinesis resources. A Terraform run fails when this is not present.
106             #
107             # The code that follows just returns a successful response, bypassing the 400
108             # response that kinesalite returns.
109             #
110             response = Response()
111             response.status_code = 200
112             content = {
113                 'CurrentShardCount': 1,
114                 'StreamName': data['StreamName'],
115                 'TargetShardCount': data['TargetShardCount']
116             }
117             response.encoding = 'UTF-8'
118             response._content = json.dumps(content)
119             return response
120 
121 
122 # instantiate listener
123 UPDATE_KINESIS = ProxyListenerKinesis()
124 
125 
126 def kinesis_error_response(data, action):
127     error_response = Response()
128 
129     if action == ACTION_PUT_RECORD:
130         error_response.status_code = 400
131         content = {
132             'ErrorCode': 'ProvisionedThroughputExceededException',
133             'ErrorMessage': 'Rate exceeded for shard X in stream Y under account Z.'
134         }
135     else:
136         error_response.status_code = 200
137         content = {'FailedRecordCount': 1, 'Records': []}
138         for record in data.get('Records', []):
139             content['Records'].append({
140                 'ErrorCode': 'ProvisionedThroughputExceededException',
141                 'ErrorMessage': 'Rate exceeded for shard X in stream Y under account Z.'
142             })
143 
144     error_response._content = json.dumps(content)
145     return error_response
146
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/localstack/services/kinesis/kinesis_listener.py b/localstack/services/kinesis/kinesis_listener.py
--- a/localstack/services/kinesis/kinesis_listener.py
+++ b/localstack/services/kinesis/kinesis_listener.py
@@ -84,18 +84,19 @@
         elif action == ACTION_PUT_RECORDS:
             event_records = []
             response_body = json.loads(to_str(response.content))
-            response_records = response_body['Records']
-            records = data['Records']
-            for index in range(0, len(records)):
-                record = records[index]
-                event_record = {
-                    'data': record['Data'],
-                    'partitionKey': record['PartitionKey'],
-                    'sequenceNumber': response_records[index].get('SequenceNumber')
-                }
-                event_records.append(event_record)
-            stream_name = data['StreamName']
-            lambda_api.process_kinesis_records(event_records, stream_name)
+            if 'Records' in response_body:
+                response_records = response_body['Records']
+                records = data['Records']
+                for index in range(0, len(records)):
+                    record = records[index]
+                    event_record = {
+                        'data': record['Data'],
+                        'partitionKey': record['PartitionKey'],
+                        'sequenceNumber': response_records[index].get('SequenceNumber')
+                    }
+                    event_records.append(event_record)
+                stream_name = data['StreamName']
+                lambda_api.process_kinesis_records(event_records, stream_name)
         elif action == ACTION_UPDATE_SHARD_COUNT:
             # Currently kinesalite, which backs the Kinesis implementation for localstack, does
             # not support UpdateShardCount:

{"golden_diff": "diff --git a/localstack/services/kinesis/kinesis_listener.py b/localstack/services/kinesis/kinesis_listener.py\n--- a/localstack/services/kinesis/kinesis_listener.py\n+++ b/localstack/services/kinesis/kinesis_listener.py\n@@ -84,18 +84,19 @@\n         elif action == ACTION_PUT_RECORDS:\n             event_records = []\n             response_body = json.loads(to_str(response.content))\n-            response_records = response_body['Records']\n-            records = data['Records']\n-            for index in range(0, len(records)):\n-                record = records[index]\n-                event_record = {\n-                    'data': record['Data'],\n-                    'partitionKey': record['PartitionKey'],\n-                    'sequenceNumber': response_records[index].get('SequenceNumber')\n-                }\n-                event_records.append(event_record)\n-            stream_name = data['StreamName']\n-            lambda_api.process_kinesis_records(event_records, stream_name)\n+            if 'Records' in response_body:\n+                response_records = response_body['Records']\n+                records = data['Records']\n+                for index in range(0, len(records)):\n+                    record = records[index]\n+                    event_record = {\n+                        'data': record['Data'],\n+                        'partitionKey': record['PartitionKey'],\n+                        'sequenceNumber': response_records[index].get('SequenceNumber')\n+                    }\n+                    event_records.append(event_record)\n+                stream_name = data['StreamName']\n+                lambda_api.process_kinesis_records(event_records, stream_name)\n         elif action == ACTION_UPDATE_SHARD_COUNT:\n             # Currently kinesalite, which backs the Kinesis implementation for localstack, does\n             # not support UpdateShardCount:\n", "issue": "Kinesis putRecords error\nIt seems that putRecords causes the following error:\r\n\r\n```\r\nStarting mock Kinesis (http port 4568)...\r\nStarting mock S3 (http port 4572)...\r\nStarting mock Firehose service (http port 4573)...\r\nStarting mock Lambda service (http port 4574)...\r\nListening at http://:::4565\r\n* Running on http://0.0.0.0:4563/ (Press CTRL+C to quit)\r\n127.0.0.1 - - [08/May/2018 13:52:25] \"GET / HTTP/1.1\" 200 -\r\nReady.\r\nr127.0.0.1 - - [08/May/2018 13:56:43] \"PUT /prd1541-qa1-vf-sms-send-stream-archive HTTP/1.1\" 200 -\r\n127.0.0.1 - - [08/May/2018 13:56:43] \"HEAD /prd1541-qa1-vf-sms-send-stream-archive HTTP/1.1\" 200 -\r\n2018-05-08T13:56:43:ERROR:localstack.services.generic_proxy: Error forwarding request: 'Records' Traceback (most recent call last):\r\n  File \"/opt/code/localstack/localstack/services/generic_proxy.py\", line 215, in forward\r\n    updated_response = self.proxy.update_listener.return_response(**kwargs)\r\n  File \"/opt/code/localstack/localstack/services/kinesis/kinesis_listener.py\", line 49, in return_response\r\n    response_records = response_body['Records']\r\nKeyError: 'Records'\r\n\r\n2018-05-08T13:56:43:ERROR:localstack.services.generic_proxy: Error forwarding request: 'Records' Traceback (most recent call last):\r\n  File \"/opt/code/localstack/localstack/services/generic_proxy.py\", line 215, in forward\r\n    updated_response = self.proxy.update_listener.return_response(**kwargs)\r\n  File \"/opt/code/localstack/localstack/services/kinesis/kinesis_listener.py\", line 49, in return_response\r\n    response_records = response_body['Records']\r\nKeyError: 'Records'\r\n\r\n2018-05-08T13:56:43:ERROR:localstack.services.generic_proxy: Error forwarding request: 'Records' Traceback (most recent call last):\r\n  File \"/opt/code/localstack/localstack/services/generic_proxy.py\", line 215, in forward\r\n    updated_response = self.proxy.update_listener.return_response(**kwargs)\r\n  File \"/opt/code/localstack/localstack/services/kinesis/kinesis_listener.py\", line 49, in return_response\r\n    response_records = response_body['Records']\r\nKeyError: 'Records'\r\n```\r\n\r\nI'm using the latest localstack image and my `Kinesis.putRecords` call goes through the Javascript AWS SDK: \r\n\r\n```\r\n...\r\n  const result = await client.putRecords({\r\n    StreamName,\r\n    Records: records.map(data => ({\r\n      Data: new Buffer(JSON.stringify(data)),\r\n      PartitionKey: 'testPartition'\r\n    }))\r\n  }).promise();\r\n...\r\n```\r\n\r\nIt seems like there's a mismatch int the expected format in `kinesis_listener.py`.\n", "before_files": [{"content": "import json\nimport random\nfrom requests.models import Response\nfrom localstack import config\nfrom localstack.utils.common import to_str\nfrom localstack.utils.analytics import event_publisher\nfrom localstack.services.awslambda import lambda_api\nfrom localstack.services.generic_proxy import ProxyListener\n\n# action headers\nACTION_PREFIX = 'Kinesis_20131202'\nACTION_PUT_RECORD = '%s.PutRecord' % ACTION_PREFIX\nACTION_PUT_RECORDS = '%s.PutRecords' % ACTION_PREFIX\nACTION_CREATE_STREAM = '%s.CreateStream' % ACTION_PREFIX\nACTION_DELETE_STREAM = '%s.DeleteStream' % ACTION_PREFIX\nACTION_UPDATE_SHARD_COUNT = '%s.UpdateShardCount' % ACTION_PREFIX\n\n\nclass ProxyListenerKinesis(ProxyListener):\n\n    def forward_request(self, method, path, data, headers):\n        data = json.loads(to_str(data))\n        action = headers.get('X-Amz-Target')\n\n        if action == '%s.DescribeStreamSummary' % ACTION_PREFIX:\n            stream_arn = data.get('StreamARN') or data['StreamName']\n            # TODO fix values below\n            result = {\n                'StreamDescriptionSummary': {\n                    'ConsumerCount': 0,\n                    'EnhancedMonitoring': [],\n                    'KeyId': 'string',\n                    'OpenShardCount': 0,\n                    'RetentionPeriodHours': 1,\n                    'StreamARN': stream_arn,\n                    # 'StreamCreationTimestamp': number,\n                    'StreamName': data['StreamName'],\n                    'StreamStatus': 'ACTIVE'\n                }\n            }\n            return result\n        if action == '%s.DescribeStreamConsumer' % ACTION_PREFIX:\n            consumer_arn = data.get('ConsumerARN') or data['ConsumerName']\n            consumer_name = data.get('ConsumerName') or data['ConsumerARN']\n            result = {\n                'ConsumerDescription': {\n                    'ConsumerARN': consumer_arn,\n                    # 'ConsumerCreationTimestamp': number,\n                    'ConsumerName': consumer_name,\n                    'ConsumerStatus': 'ACTIVE',\n                    'StreamARN': data.get('StreamARN')\n                }\n            }\n            return result\n\n        if random.random() < config.KINESIS_ERROR_PROBABILITY:\n            action = headers.get('X-Amz-Target')\n            if action in [ACTION_PUT_RECORD, ACTION_PUT_RECORDS]:\n                return kinesis_error_response(data, action)\n        return True\n\n    def return_response(self, method, path, data, headers, response):\n        action = headers.get('X-Amz-Target')\n        data = json.loads(to_str(data))\n\n        records = []\n        if action in (ACTION_CREATE_STREAM, ACTION_DELETE_STREAM):\n            event_type = (event_publisher.EVENT_KINESIS_CREATE_STREAM if action == ACTION_CREATE_STREAM\n                          else event_publisher.EVENT_KINESIS_DELETE_STREAM)\n            payload = {'n': event_publisher.get_hash(data.get('StreamName'))}\n            if action == ACTION_CREATE_STREAM:\n                payload['s'] = data.get('ShardCount')\n            event_publisher.fire_event(event_type, payload=payload)\n        elif action == ACTION_PUT_RECORD:\n            response_body = json.loads(to_str(response.content))\n            event_record = {\n                'data': data['Data'],\n                'partitionKey': data['PartitionKey'],\n                'sequenceNumber': response_body.get('SequenceNumber')\n            }\n            event_records = [event_record]\n            stream_name = data['StreamName']\n            lambda_api.process_kinesis_records(event_records, stream_name)\n        elif action == ACTION_PUT_RECORDS:\n            event_records = []\n            response_body = json.loads(to_str(response.content))\n            response_records = response_body['Records']\n            records = data['Records']\n            for index in range(0, len(records)):\n                record = records[index]\n                event_record = {\n                    'data': record['Data'],\n                    'partitionKey': record['PartitionKey'],\n                    'sequenceNumber': response_records[index].get('SequenceNumber')\n                }\n                event_records.append(event_record)\n            stream_name = data['StreamName']\n            lambda_api.process_kinesis_records(event_records, stream_name)\n        elif action == ACTION_UPDATE_SHARD_COUNT:\n            # Currently kinesalite, which backs the Kinesis implementation for localstack, does\n            # not support UpdateShardCount:\n            # https://github.com/mhart/kinesalite/issues/61\n            #\n            # [Terraform](https://www.terraform.io) makes the call to UpdateShardCount when it\n            # applies Kinesis resources. A Terraform run fails when this is not present.\n            #\n            # The code that follows just returns a successful response, bypassing the 400\n            # response that kinesalite returns.\n            #\n            response = Response()\n            response.status_code = 200\n            content = {\n                'CurrentShardCount': 1,\n                'StreamName': data['StreamName'],\n                'TargetShardCount': data['TargetShardCount']\n            }\n            response.encoding = 'UTF-8'\n            response._content = json.dumps(content)\n            return response\n\n\n# instantiate listener\nUPDATE_KINESIS = ProxyListenerKinesis()\n\n\ndef kinesis_error_response(data, action):\n    error_response = Response()\n\n    if action == ACTION_PUT_RECORD:\n        error_response.status_code = 400\n        content = {\n            'ErrorCode': 'ProvisionedThroughputExceededException',\n            'ErrorMessage': 'Rate exceeded for shard X in stream Y under account Z.'\n        }\n    else:\n        error_response.status_code = 200\n        content = {'FailedRecordCount': 1, 'Records': []}\n        for record in data.get('Records', []):\n            content['Records'].append({\n                'ErrorCode': 'ProvisionedThroughputExceededException',\n                'ErrorMessage': 'Rate exceeded for shard X in stream Y under account Z.'\n            })\n\n    error_response._content = json.dumps(content)\n    return error_response\n", "path": "localstack/services/kinesis/kinesis_listener.py"}], "after_files": [{"content": "import json\nimport random\nfrom requests.models import Response\nfrom localstack import config\nfrom localstack.utils.common import to_str\nfrom localstack.utils.analytics import event_publisher\nfrom localstack.services.awslambda import lambda_api\nfrom localstack.services.generic_proxy import ProxyListener\n\n# action headers\nACTION_PREFIX = 'Kinesis_20131202'\nACTION_PUT_RECORD = '%s.PutRecord' % ACTION_PREFIX\nACTION_PUT_RECORDS = '%s.PutRecords' % ACTION_PREFIX\nACTION_CREATE_STREAM = '%s.CreateStream' % ACTION_PREFIX\nACTION_DELETE_STREAM = '%s.DeleteStream' % ACTION_PREFIX\nACTION_UPDATE_SHARD_COUNT = '%s.UpdateShardCount' % ACTION_PREFIX\n\n\nclass ProxyListenerKinesis(ProxyListener):\n\n    def forward_request(self, method, path, data, headers):\n        data = json.loads(to_str(data))\n        action = headers.get('X-Amz-Target')\n\n        if action == '%s.DescribeStreamSummary' % ACTION_PREFIX:\n            stream_arn = data.get('StreamARN') or data['StreamName']\n            # TODO fix values below\n            result = {\n                'StreamDescriptionSummary': {\n                    'ConsumerCount': 0,\n                    'EnhancedMonitoring': [],\n                    'KeyId': 'string',\n                    'OpenShardCount': 0,\n                    'RetentionPeriodHours': 1,\n                    'StreamARN': stream_arn,\n                    # 'StreamCreationTimestamp': number,\n                    'StreamName': data['StreamName'],\n                    'StreamStatus': 'ACTIVE'\n                }\n            }\n            return result\n        if action == '%s.DescribeStreamConsumer' % ACTION_PREFIX:\n            consumer_arn = data.get('ConsumerARN') or data['ConsumerName']\n            consumer_name = data.get('ConsumerName') or data['ConsumerARN']\n            result = {\n                'ConsumerDescription': {\n                    'ConsumerARN': consumer_arn,\n                    # 'ConsumerCreationTimestamp': number,\n                    'ConsumerName': consumer_name,\n                    'ConsumerStatus': 'ACTIVE',\n                    'StreamARN': data.get('StreamARN')\n                }\n            }\n            return result\n\n        if random.random() < config.KINESIS_ERROR_PROBABILITY:\n            action = headers.get('X-Amz-Target')\n            if action in [ACTION_PUT_RECORD, ACTION_PUT_RECORDS]:\n                return kinesis_error_response(data, action)\n        return True\n\n    def return_response(self, method, path, data, headers, response):\n        action = headers.get('X-Amz-Target')\n        data = json.loads(to_str(data))\n\n        records = []\n        if action in (ACTION_CREATE_STREAM, ACTION_DELETE_STREAM):\n            event_type = (event_publisher.EVENT_KINESIS_CREATE_STREAM if action == ACTION_CREATE_STREAM\n                          else event_publisher.EVENT_KINESIS_DELETE_STREAM)\n            payload = {'n': event_publisher.get_hash(data.get('StreamName'))}\n            if action == ACTION_CREATE_STREAM:\n                payload['s'] = data.get('ShardCount')\n            event_publisher.fire_event(event_type, payload=payload)\n        elif action == ACTION_PUT_RECORD:\n            response_body = json.loads(to_str(response.content))\n            event_record = {\n                'data': data['Data'],\n                'partitionKey': data['PartitionKey'],\n                'sequenceNumber': response_body.get('SequenceNumber')\n            }\n            event_records = [event_record]\n            stream_name = data['StreamName']\n            lambda_api.process_kinesis_records(event_records, stream_name)\n        elif action == ACTION_PUT_RECORDS:\n            event_records = []\n            response_body = json.loads(to_str(response.content))\n            if 'Records' in response_body:\n                response_records = response_body['Records']\n                records = data['Records']\n                for index in range(0, len(records)):\n                    record = records[index]\n                    event_record = {\n                        'data': record['Data'],\n                        'partitionKey': record['PartitionKey'],\n                        'sequenceNumber': response_records[index].get('SequenceNumber')\n                    }\n                    event_records.append(event_record)\n                stream_name = data['StreamName']\n                lambda_api.process_kinesis_records(event_records, stream_name)\n        elif action == ACTION_UPDATE_SHARD_COUNT:\n            # Currently kinesalite, which backs the Kinesis implementation for localstack, does\n            # not support UpdateShardCount:\n            # https://github.com/mhart/kinesalite/issues/61\n            #\n            # [Terraform](https://www.terraform.io) makes the call to UpdateShardCount when it\n            # applies Kinesis resources. A Terraform run fails when this is not present.\n            #\n            # The code that follows just returns a successful response, bypassing the 400\n            # response that kinesalite returns.\n            #\n            response = Response()\n            response.status_code = 200\n            content = {\n                'CurrentShardCount': 1,\n                'StreamName': data['StreamName'],\n                'TargetShardCount': data['TargetShardCount']\n            }\n            response.encoding = 'UTF-8'\n            response._content = json.dumps(content)\n            return response\n\n\n# instantiate listener\nUPDATE_KINESIS = ProxyListenerKinesis()\n\n\ndef kinesis_error_response(data, action):\n    error_response = Response()\n\n    if action == ACTION_PUT_RECORD:\n        error_response.status_code = 400\n        content = {\n            'ErrorCode': 'ProvisionedThroughputExceededException',\n            'ErrorMessage': 'Rate exceeded for shard X in stream Y under account Z.'\n        }\n    else:\n        error_response.status_code = 200\n        content = {'FailedRecordCount': 1, 'Records': []}\n        for record in data.get('Records', []):\n            content['Records'].append({\n                'ErrorCode': 'ProvisionedThroughputExceededException',\n                'ErrorMessage': 'Rate exceeded for shard X in stream Y under account Z.'\n            })\n\n    error_response._content = json.dumps(content)\n    return error_response\n", "path": "localstack/services/kinesis/kinesis_listener.py"}]}