We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Elasticsearch domain managed by Terraform cannot be updated; request for /tags/? returns 404
<!-- Love localstack? Please consider supporting our collective:
👉  https://opencollective.com/localstack/donate -->

We use Terraform to create and update resources in Localstack, which has worked for services like S3 and Dynamo so far.

We hit an issue with Elasticsearch domains, where the domain is created successfully but Terraform fails to apply in subsequent runs, when it makes a request to:

```
logs: ---[ REQUEST POST-SIGN ]-----------------------------
logs: GET /2015-01-01/tags/?arn=arn%3Aaws%3Aes%3Aus-east-1%3A000000000000%3Adomain%2Fepdam-local-amd HTTP/1.1
logs: Host: localhost:4578
logs: User-Agent: aws-sdk-go/1.14.31 (go1.9.2; darwin; amd64) APN/1.0 HashiCorp/1.0 Terraform/0.11.8-dev
logs: Authorization: AWS4-HMAC-SHA256 Credential=mock_access_key/20190221/us-west-2/es/aws4_request, SignedHeaders=host;x-amz-date, Signature=26f42429e2af2240466635ab9202c8888617afe9be7b8ef91a8831d6b4160bd1
logs: X-Amz-Date: 20190221T191447Z
logs: Accept-Encoding: gzip
```

and the response is:

```
logs: ---[ RESPONSE ]--------------------------------------
logs: HTTP/1.0 404 NOT FOUND
logs: Connection: close
logs: Content-Length: 233
logs: Access-Control-Allow-Origin: *
logs: Content-Type: text/html
logs: Date: Thu, 21 Feb 2019 19:14:47 GMT
logs: Server: Werkzeug/0.14.1 Python/2.7.15
```

While a request to `localhost:4578/2015-01-01/tags/?arn=...` gets 404, a request to `localhost:4578/2015-01-01/tags?arn=...`, (without the `/` before the query params), is successful.

The reason we are reporting this against Localstack and not [terraform](https://github.com/hashicorp/terraform) or [terraform-provider-aws](https://github.com/terraform-providers/terraform-provider-aws) is that the AWS REST API apparently supports requests with slashes before query parameters, or else Terraform could not be used to manage Elasticsearch domains in AWS.

--- 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/es/es_api.py`
Content:
```
1 import json
2 import time
3 from random import randint
4 from flask import Flask, jsonify, request, make_response
5 from localstack.services import generic_proxy
6 from localstack.utils.aws import aws_stack
7 from localstack.constants import TEST_AWS_ACCOUNT_ID
8 from localstack.utils.common import to_str
9 from localstack.utils.analytics import event_publisher
10 
11 APP_NAME = 'es_api'
12 API_PREFIX = '/2015-01-01'
13 
14 ES_DOMAINS = {}
15 
16 app = Flask(APP_NAME)
17 
18 
19 def error_response(error_type, code=400, message='Unknown error.'):
20     if not message:
21         if error_type == 'ResourceNotFoundException':
22             message = 'Resource not found.'
23         elif error_type == 'ResourceAlreadyExistsException':
24             message = 'Resource already exists.'
25     response = make_response(jsonify({'error': message}))
26     response.headers['x-amzn-errortype'] = error_type
27     return response, code
28 
29 
30 def get_domain_config_status():
31     return {
32         'CreationDate': '%.2f' % time.time(),
33         'PendingDeletion': False,
34         'State': 'Active',
35         'UpdateDate': '%.2f' % time.time(),
36         'UpdateVersion': randint(1, 100)
37     }
38 
39 
40 def get_domain_config(domain_name):
41     config_status = get_domain_config_status()
42     return {
43         'DomainConfig': {
44             'AccessPolicies': {
45                 'Options': '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::%s:root"},"Action":"es:*","Resource":"arn:aws:es:%s:%s:domain/%s/*"}]}' % (TEST_AWS_ACCOUNT_ID, aws_stack.get_region(), TEST_AWS_ACCOUNT_ID, domain_name),  # noqa: E501
46                 'Status': config_status
47             },
48             'AdvancedOptions': {
49                 'Options': {
50                     'indices.fielddata.cache.size': '',
51                     'rest.action.multi.allow_explicit_index': 'true'
52                 },
53                 'Status': config_status
54             },
55             'EBSOptions': {
56                 'Options': {
57                     'EBSEnabled': True,
58                     'EncryptionEnabled': False,
59                     'Iops': 0,
60                     'VolumeSize': 10,
61                     'VolumeType': 'gp2'
62                 },
63                 'Status': config_status
64             },
65             'ElasticsearchClusterConfig': {
66                 'Options': {
67                     'DedicatedMasterCount': 1,
68                     'DedicatedMasterEnabled': True,
69                     'DedicatedMasterType': 'm3.medium.elasticsearch',
70                     'InstanceCount': 1,
71                     'InstanceType': 'm3.medium.elasticsearch',
72                     'ZoneAwarenessEnabled': False
73                 },
74                 'Status': config_status
75             },
76             'ElasticsearchVersion': {
77                 'Options': '5.3',
78                 'Status': config_status
79             },
80             'EncryptionAtRestOptions': {
81                 'Options': {
82                     'Enabled': False,
83                     'KmsKeyId': ''
84                 },
85                 'Status': config_status
86             },
87             'LogPublishingOptions': {
88                 'Options': {
89                     'INDEX_SLOW_LOGS': {
90                         'CloudWatchLogsLogGroupArn': 'arn:aws:logs:%s:%s:log-group:sample-domain' % (aws_stack.get_region(), TEST_AWS_ACCOUNT_ID),  # noqa: E501
91                         'Enabled': False
92                     },
93                     'SEARCH_SLOW_LOGS': {
94                         'CloudWatchLogsLogGroupArn': 'arn:aws:logs:%s:%s:log-group:sample-domain' % (aws_stack.get_region(), TEST_AWS_ACCOUNT_ID),  # noqa: E501
95                         'Enabled': False,
96                     }
97                 },
98                 'Status': config_status
99             },
100             'SnapshotOptions': {
101                 'Options': {
102                     'AutomatedSnapshotStartHour': randint(0, 23)
103                 },
104                 'Status': config_status
105             },
106             'VPCOptions': {
107                 'Options': {
108                     'AvailabilityZones': [
109                         'us-east-1b'
110                     ],
111                     'SecurityGroupIds': [
112                         'sg-12345678'
113                     ],
114                     'SubnetIds': [
115                         'subnet-12345678'
116                     ],
117                     'VPCId': 'vpc-12345678'
118                 },
119                 'Status': config_status
120             }
121         }
122     }
123 
124 
125 def get_domain_status(domain_name, deleted=False):
126     return {
127         'DomainStatus': {
128             'ARN': 'arn:aws:es:%s:%s:domain/%s' % (aws_stack.get_region(), TEST_AWS_ACCOUNT_ID, domain_name),
129             'Created': True,
130             'Deleted': deleted,
131             'DomainId': '%s/%s' % (TEST_AWS_ACCOUNT_ID, domain_name),
132             'DomainName': domain_name,
133             'ElasticsearchClusterConfig': {
134                 'DedicatedMasterCount': 1,
135                 'DedicatedMasterEnabled': True,
136                 'DedicatedMasterType': 'm3.medium.elasticsearch',
137                 'InstanceCount': 1,
138                 'InstanceType': 'm3.medium.elasticsearch',
139                 'ZoneAwarenessEnabled': False
140             },
141             'ElasticsearchVersion': '6.7',
142             'Endpoint': aws_stack.get_elasticsearch_endpoint(domain_name),
143             'Processing': False,
144             'EBSOptions': {
145                 'EBSEnabled': True,
146                 'VolumeType': 'gp2',
147                 'VolumeSize': 10,
148                 'Iops': 0
149             },
150         }
151     }
152 
153 
154 @app.route('%s/domain' % API_PREFIX, methods=['GET'])
155 def list_domain_names():
156     result = {
157         'DomainNames': [{'DomainName': name} for name in ES_DOMAINS.keys()]
158     }
159     return jsonify(result)
160 
161 
162 @app.route('%s/es/domain' % API_PREFIX, methods=['POST'])
163 def create_domain():
164     data = json.loads(to_str(request.data))
165     domain_name = data['DomainName']
166     if domain_name in ES_DOMAINS:
167         return error_response(error_type='ResourceAlreadyExistsException')
168     ES_DOMAINS[domain_name] = data
169     result = get_domain_status(domain_name)
170     # record event
171     event_publisher.fire_event(event_publisher.EVENT_ES_CREATE_DOMAIN,
172         payload={'n': event_publisher.get_hash(domain_name)})
173     return jsonify(result)
174 
175 
176 @app.route('%s/es/domain/<domain_name>' % API_PREFIX, methods=['GET'])
177 def describe_domain(domain_name):
178     if domain_name not in ES_DOMAINS:
179         return error_response(error_type='ResourceNotFoundException')
180     result = get_domain_status(domain_name)
181     return jsonify(result)
182 
183 
184 @app.route('%s/es/domain/<domain_name>/config' % API_PREFIX, methods=['GET', 'POST'])
185 def domain_config(domain_name):
186     config = get_domain_config(domain_name)
187     return jsonify(config)
188 
189 
190 @app.route('%s/es/domain/<domain_name>' % API_PREFIX, methods=['DELETE'])
191 def delete_domain(domain_name):
192     if domain_name not in ES_DOMAINS:
193         return error_response(error_type='ResourceNotFoundException')
194     result = get_domain_status(domain_name, deleted=True)
195     ES_DOMAINS.pop(domain_name)
196     # record event
197     event_publisher.fire_event(event_publisher.EVENT_ES_DELETE_DOMAIN,
198         payload={'n': event_publisher.get_hash(domain_name)})
199     return jsonify(result)
200 
201 
202 @app.route('%s/tags' % API_PREFIX, methods=['GET', 'POST'])
203 def add_list_tags():
204     if request.method == 'GET' and request.args.get('arn'):
205         response = {
206             'TagList': [
207                 {
208                     'Key': 'Example1',
209                     'Value': 'Value'
210                 },
211                 {
212                     'Key': 'Example2',
213                     'Value': 'Value'
214                 }
215             ]
216         }
217         return jsonify(response)
218 
219     return jsonify({})
220 
221 
222 def serve(port, quiet=True):
223     generic_proxy.serve_flask_app(app=app, port=port, quiet=quiet)
224
```
--- 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/es/es_api.py b/localstack/services/es/es_api.py
--- a/localstack/services/es/es_api.py
+++ b/localstack/services/es/es_api.py
@@ -14,6 +14,7 @@
 ES_DOMAINS = {}
 
 app = Flask(APP_NAME)
+app.url_map.strict_slashes = False
 
 
 def error_response(error_type, code=400, message='Unknown error.'):

{"golden_diff": "diff --git a/localstack/services/es/es_api.py b/localstack/services/es/es_api.py\n--- a/localstack/services/es/es_api.py\n+++ b/localstack/services/es/es_api.py\n@@ -14,6 +14,7 @@\n ES_DOMAINS = {}\n \n app = Flask(APP_NAME)\n+app.url_map.strict_slashes = False\n \n \n def error_response(error_type, code=400, message='Unknown error.'):\n", "issue": "Elasticsearch domain managed by Terraform cannot be updated; request for /tags/? returns 404\n<!-- Love localstack? Please consider supporting our collective:\r\n\ud83d\udc49  https://opencollective.com/localstack/donate -->\r\n\r\nWe use Terraform to create and update resources in Localstack, which has worked for services like S3 and Dynamo so far.\r\n\r\nWe hit an issue with Elasticsearch domains, where the domain is created successfully but Terraform fails to apply in subsequent runs, when it makes a request to:\r\n\r\n```\r\nlogs: ---[ REQUEST POST-SIGN ]-----------------------------\r\nlogs: GET /2015-01-01/tags/?arn=arn%3Aaws%3Aes%3Aus-east-1%3A000000000000%3Adomain%2Fepdam-local-amd HTTP/1.1\r\nlogs: Host: localhost:4578\r\nlogs: User-Agent: aws-sdk-go/1.14.31 (go1.9.2; darwin; amd64) APN/1.0 HashiCorp/1.0 Terraform/0.11.8-dev\r\nlogs: Authorization: AWS4-HMAC-SHA256 Credential=mock_access_key/20190221/us-west-2/es/aws4_request, SignedHeaders=host;x-amz-date, Signature=26f42429e2af2240466635ab9202c8888617afe9be7b8ef91a8831d6b4160bd1\r\nlogs: X-Amz-Date: 20190221T191447Z\r\nlogs: Accept-Encoding: gzip\r\n```\r\n\r\nand the response is:\r\n\r\n```\r\nlogs: ---[ RESPONSE ]--------------------------------------\r\nlogs: HTTP/1.0 404 NOT FOUND\r\nlogs: Connection: close\r\nlogs: Content-Length: 233\r\nlogs: Access-Control-Allow-Origin: *\r\nlogs: Content-Type: text/html\r\nlogs: Date: Thu, 21 Feb 2019 19:14:47 GMT\r\nlogs: Server: Werkzeug/0.14.1 Python/2.7.15\r\n```\r\n\r\nWhile a request to `localhost:4578/2015-01-01/tags/?arn=...` gets 404, a request to `localhost:4578/2015-01-01/tags?arn=...`, (without the `/` before the query params), is successful.\r\n\r\nThe reason we are reporting this against Localstack and not [terraform](https://github.com/hashicorp/terraform) or [terraform-provider-aws](https://github.com/terraform-providers/terraform-provider-aws) is that the AWS REST API apparently supports requests with slashes before query parameters, or else Terraform could not be used to manage Elasticsearch domains in AWS.\n", "before_files": [{"content": "import json\nimport time\nfrom random import randint\nfrom flask import Flask, jsonify, request, make_response\nfrom localstack.services import generic_proxy\nfrom localstack.utils.aws import aws_stack\nfrom localstack.constants import TEST_AWS_ACCOUNT_ID\nfrom localstack.utils.common import to_str\nfrom localstack.utils.analytics import event_publisher\n\nAPP_NAME = 'es_api'\nAPI_PREFIX = '/2015-01-01'\n\nES_DOMAINS = {}\n\napp = Flask(APP_NAME)\n\n\ndef error_response(error_type, code=400, message='Unknown error.'):\n    if not message:\n        if error_type == 'ResourceNotFoundException':\n            message = 'Resource not found.'\n        elif error_type == 'ResourceAlreadyExistsException':\n            message = 'Resource already exists.'\n    response = make_response(jsonify({'error': message}))\n    response.headers['x-amzn-errortype'] = error_type\n    return response, code\n\n\ndef get_domain_config_status():\n    return {\n        'CreationDate': '%.2f' % time.time(),\n        'PendingDeletion': False,\n        'State': 'Active',\n        'UpdateDate': '%.2f' % time.time(),\n        'UpdateVersion': randint(1, 100)\n    }\n\n\ndef get_domain_config(domain_name):\n    config_status = get_domain_config_status()\n    return {\n        'DomainConfig': {\n            'AccessPolicies': {\n                'Options': '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::%s:root\"},\"Action\":\"es:*\",\"Resource\":\"arn:aws:es:%s:%s:domain/%s/*\"}]}' % (TEST_AWS_ACCOUNT_ID, aws_stack.get_region(), TEST_AWS_ACCOUNT_ID, domain_name),  # noqa: E501\n                'Status': config_status\n            },\n            'AdvancedOptions': {\n                'Options': {\n                    'indices.fielddata.cache.size': '',\n                    'rest.action.multi.allow_explicit_index': 'true'\n                },\n                'Status': config_status\n            },\n            'EBSOptions': {\n                'Options': {\n                    'EBSEnabled': True,\n                    'EncryptionEnabled': False,\n                    'Iops': 0,\n                    'VolumeSize': 10,\n                    'VolumeType': 'gp2'\n                },\n                'Status': config_status\n            },\n            'ElasticsearchClusterConfig': {\n                'Options': {\n                    'DedicatedMasterCount': 1,\n                    'DedicatedMasterEnabled': True,\n                    'DedicatedMasterType': 'm3.medium.elasticsearch',\n                    'InstanceCount': 1,\n                    'InstanceType': 'm3.medium.elasticsearch',\n                    'ZoneAwarenessEnabled': False\n                },\n                'Status': config_status\n            },\n            'ElasticsearchVersion': {\n                'Options': '5.3',\n                'Status': config_status\n            },\n            'EncryptionAtRestOptions': {\n                'Options': {\n                    'Enabled': False,\n                    'KmsKeyId': ''\n                },\n                'Status': config_status\n            },\n            'LogPublishingOptions': {\n                'Options': {\n                    'INDEX_SLOW_LOGS': {\n                        'CloudWatchLogsLogGroupArn': 'arn:aws:logs:%s:%s:log-group:sample-domain' % (aws_stack.get_region(), TEST_AWS_ACCOUNT_ID),  # noqa: E501\n                        'Enabled': False\n                    },\n                    'SEARCH_SLOW_LOGS': {\n                        'CloudWatchLogsLogGroupArn': 'arn:aws:logs:%s:%s:log-group:sample-domain' % (aws_stack.get_region(), TEST_AWS_ACCOUNT_ID),  # noqa: E501\n                        'Enabled': False,\n                    }\n                },\n                'Status': config_status\n            },\n            'SnapshotOptions': {\n                'Options': {\n                    'AutomatedSnapshotStartHour': randint(0, 23)\n                },\n                'Status': config_status\n            },\n            'VPCOptions': {\n                'Options': {\n                    'AvailabilityZones': [\n                        'us-east-1b'\n                    ],\n                    'SecurityGroupIds': [\n                        'sg-12345678'\n                    ],\n                    'SubnetIds': [\n                        'subnet-12345678'\n                    ],\n                    'VPCId': 'vpc-12345678'\n                },\n                'Status': config_status\n            }\n        }\n    }\n\n\ndef get_domain_status(domain_name, deleted=False):\n    return {\n        'DomainStatus': {\n            'ARN': 'arn:aws:es:%s:%s:domain/%s' % (aws_stack.get_region(), TEST_AWS_ACCOUNT_ID, domain_name),\n            'Created': True,\n            'Deleted': deleted,\n            'DomainId': '%s/%s' % (TEST_AWS_ACCOUNT_ID, domain_name),\n            'DomainName': domain_name,\n            'ElasticsearchClusterConfig': {\n                'DedicatedMasterCount': 1,\n                'DedicatedMasterEnabled': True,\n                'DedicatedMasterType': 'm3.medium.elasticsearch',\n                'InstanceCount': 1,\n                'InstanceType': 'm3.medium.elasticsearch',\n                'ZoneAwarenessEnabled': False\n            },\n            'ElasticsearchVersion': '6.7',\n            'Endpoint': aws_stack.get_elasticsearch_endpoint(domain_name),\n            'Processing': False,\n            'EBSOptions': {\n                'EBSEnabled': True,\n                'VolumeType': 'gp2',\n                'VolumeSize': 10,\n                'Iops': 0\n            },\n        }\n    }\n\n\n@app.route('%s/domain' % API_PREFIX, methods=['GET'])\ndef list_domain_names():\n    result = {\n        'DomainNames': [{'DomainName': name} for name in ES_DOMAINS.keys()]\n    }\n    return jsonify(result)\n\n\n@app.route('%s/es/domain' % API_PREFIX, methods=['POST'])\ndef create_domain():\n    data = json.loads(to_str(request.data))\n    domain_name = data['DomainName']\n    if domain_name in ES_DOMAINS:\n        return error_response(error_type='ResourceAlreadyExistsException')\n    ES_DOMAINS[domain_name] = data\n    result = get_domain_status(domain_name)\n    # record event\n    event_publisher.fire_event(event_publisher.EVENT_ES_CREATE_DOMAIN,\n        payload={'n': event_publisher.get_hash(domain_name)})\n    return jsonify(result)\n\n\n@app.route('%s/es/domain/<domain_name>' % API_PREFIX, methods=['GET'])\ndef describe_domain(domain_name):\n    if domain_name not in ES_DOMAINS:\n        return error_response(error_type='ResourceNotFoundException')\n    result = get_domain_status(domain_name)\n    return jsonify(result)\n\n\n@app.route('%s/es/domain/<domain_name>/config' % API_PREFIX, methods=['GET', 'POST'])\ndef domain_config(domain_name):\n    config = get_domain_config(domain_name)\n    return jsonify(config)\n\n\n@app.route('%s/es/domain/<domain_name>' % API_PREFIX, methods=['DELETE'])\ndef delete_domain(domain_name):\n    if domain_name not in ES_DOMAINS:\n        return error_response(error_type='ResourceNotFoundException')\n    result = get_domain_status(domain_name, deleted=True)\n    ES_DOMAINS.pop(domain_name)\n    # record event\n    event_publisher.fire_event(event_publisher.EVENT_ES_DELETE_DOMAIN,\n        payload={'n': event_publisher.get_hash(domain_name)})\n    return jsonify(result)\n\n\n@app.route('%s/tags' % API_PREFIX, methods=['GET', 'POST'])\ndef add_list_tags():\n    if request.method == 'GET' and request.args.get('arn'):\n        response = {\n            'TagList': [\n                {\n                    'Key': 'Example1',\n                    'Value': 'Value'\n                },\n                {\n                    'Key': 'Example2',\n                    'Value': 'Value'\n                }\n            ]\n        }\n        return jsonify(response)\n\n    return jsonify({})\n\n\ndef serve(port, quiet=True):\n    generic_proxy.serve_flask_app(app=app, port=port, quiet=quiet)\n", "path": "localstack/services/es/es_api.py"}], "after_files": [{"content": "import json\nimport time\nfrom random import randint\nfrom flask import Flask, jsonify, request, make_response\nfrom localstack.services import generic_proxy\nfrom localstack.utils.aws import aws_stack\nfrom localstack.constants import TEST_AWS_ACCOUNT_ID\nfrom localstack.utils.common import to_str\nfrom localstack.utils.analytics import event_publisher\n\nAPP_NAME = 'es_api'\nAPI_PREFIX = '/2015-01-01'\n\nES_DOMAINS = {}\n\napp = Flask(APP_NAME)\napp.url_map.strict_slashes = False\n\n\ndef error_response(error_type, code=400, message='Unknown error.'):\n    if not message:\n        if error_type == 'ResourceNotFoundException':\n            message = 'Resource not found.'\n        elif error_type == 'ResourceAlreadyExistsException':\n            message = 'Resource already exists.'\n    response = make_response(jsonify({'error': message}))\n    response.headers['x-amzn-errortype'] = error_type\n    return response, code\n\n\ndef get_domain_config_status():\n    return {\n        'CreationDate': '%.2f' % time.time(),\n        'PendingDeletion': False,\n        'State': 'Active',\n        'UpdateDate': '%.2f' % time.time(),\n        'UpdateVersion': randint(1, 100)\n    }\n\n\ndef get_domain_config(domain_name):\n    config_status = get_domain_config_status()\n    return {\n        'DomainConfig': {\n            'AccessPolicies': {\n                'Options': '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::%s:root\"},\"Action\":\"es:*\",\"Resource\":\"arn:aws:es:%s:%s:domain/%s/*\"}]}' % (TEST_AWS_ACCOUNT_ID, aws_stack.get_region(), TEST_AWS_ACCOUNT_ID, domain_name),  # noqa: E501\n                'Status': config_status\n            },\n            'AdvancedOptions': {\n                'Options': {\n                    'indices.fielddata.cache.size': '',\n                    'rest.action.multi.allow_explicit_index': 'true'\n                },\n                'Status': config_status\n            },\n            'EBSOptions': {\n                'Options': {\n                    'EBSEnabled': True,\n                    'EncryptionEnabled': False,\n                    'Iops': 0,\n                    'VolumeSize': 10,\n                    'VolumeType': 'gp2'\n                },\n                'Status': config_status\n            },\n            'ElasticsearchClusterConfig': {\n                'Options': {\n                    'DedicatedMasterCount': 1,\n                    'DedicatedMasterEnabled': True,\n                    'DedicatedMasterType': 'm3.medium.elasticsearch',\n                    'InstanceCount': 1,\n                    'InstanceType': 'm3.medium.elasticsearch',\n                    'ZoneAwarenessEnabled': False\n                },\n                'Status': config_status\n            },\n            'ElasticsearchVersion': {\n                'Options': '5.3',\n                'Status': config_status\n            },\n            'EncryptionAtRestOptions': {\n                'Options': {\n                    'Enabled': False,\n                    'KmsKeyId': ''\n                },\n                'Status': config_status\n            },\n            'LogPublishingOptions': {\n                'Options': {\n                    'INDEX_SLOW_LOGS': {\n                        'CloudWatchLogsLogGroupArn': 'arn:aws:logs:%s:%s:log-group:sample-domain' % (aws_stack.get_region(), TEST_AWS_ACCOUNT_ID),  # noqa: E501\n                        'Enabled': False\n                    },\n                    'SEARCH_SLOW_LOGS': {\n                        'CloudWatchLogsLogGroupArn': 'arn:aws:logs:%s:%s:log-group:sample-domain' % (aws_stack.get_region(), TEST_AWS_ACCOUNT_ID),  # noqa: E501\n                        'Enabled': False,\n                    }\n                },\n                'Status': config_status\n            },\n            'SnapshotOptions': {\n                'Options': {\n                    'AutomatedSnapshotStartHour': randint(0, 23)\n                },\n                'Status': config_status\n            },\n            'VPCOptions': {\n                'Options': {\n                    'AvailabilityZones': [\n                        'us-east-1b'\n                    ],\n                    'SecurityGroupIds': [\n                        'sg-12345678'\n                    ],\n                    'SubnetIds': [\n                        'subnet-12345678'\n                    ],\n                    'VPCId': 'vpc-12345678'\n                },\n                'Status': config_status\n            }\n        }\n    }\n\n\ndef get_domain_status(domain_name, deleted=False):\n    return {\n        'DomainStatus': {\n            'ARN': 'arn:aws:es:%s:%s:domain/%s' % (aws_stack.get_region(), TEST_AWS_ACCOUNT_ID, domain_name),\n            'Created': True,\n            'Deleted': deleted,\n            'DomainId': '%s/%s' % (TEST_AWS_ACCOUNT_ID, domain_name),\n            'DomainName': domain_name,\n            'ElasticsearchClusterConfig': {\n                'DedicatedMasterCount': 1,\n                'DedicatedMasterEnabled': True,\n                'DedicatedMasterType': 'm3.medium.elasticsearch',\n                'InstanceCount': 1,\n                'InstanceType': 'm3.medium.elasticsearch',\n                'ZoneAwarenessEnabled': False\n            },\n            'ElasticsearchVersion': '6.7',\n            'Endpoint': aws_stack.get_elasticsearch_endpoint(domain_name),\n            'Processing': False,\n            'EBSOptions': {\n                'EBSEnabled': True,\n                'VolumeType': 'gp2',\n                'VolumeSize': 10,\n                'Iops': 0\n            },\n        }\n    }\n\n\n@app.route('%s/domain' % API_PREFIX, methods=['GET'])\ndef list_domain_names():\n    result = {\n        'DomainNames': [{'DomainName': name} for name in ES_DOMAINS.keys()]\n    }\n    return jsonify(result)\n\n\n@app.route('%s/es/domain' % API_PREFIX, methods=['POST'])\ndef create_domain():\n    data = json.loads(to_str(request.data))\n    domain_name = data['DomainName']\n    if domain_name in ES_DOMAINS:\n        return error_response(error_type='ResourceAlreadyExistsException')\n    ES_DOMAINS[domain_name] = data\n    result = get_domain_status(domain_name)\n    # record event\n    event_publisher.fire_event(event_publisher.EVENT_ES_CREATE_DOMAIN,\n        payload={'n': event_publisher.get_hash(domain_name)})\n    return jsonify(result)\n\n\n@app.route('%s/es/domain/<domain_name>' % API_PREFIX, methods=['GET'])\ndef describe_domain(domain_name):\n    if domain_name not in ES_DOMAINS:\n        return error_response(error_type='ResourceNotFoundException')\n    result = get_domain_status(domain_name)\n    return jsonify(result)\n\n\n@app.route('%s/es/domain/<domain_name>/config' % API_PREFIX, methods=['GET', 'POST'])\ndef domain_config(domain_name):\n    config = get_domain_config(domain_name)\n    return jsonify(config)\n\n\n@app.route('%s/es/domain/<domain_name>' % API_PREFIX, methods=['DELETE'])\ndef delete_domain(domain_name):\n    if domain_name not in ES_DOMAINS:\n        return error_response(error_type='ResourceNotFoundException')\n    result = get_domain_status(domain_name, deleted=True)\n    ES_DOMAINS.pop(domain_name)\n    # record event\n    event_publisher.fire_event(event_publisher.EVENT_ES_DELETE_DOMAIN,\n        payload={'n': event_publisher.get_hash(domain_name)})\n    return jsonify(result)\n\n\n@app.route('%s/tags' % API_PREFIX, methods=['GET', 'POST'])\ndef add_list_tags():\n    if request.method == 'GET' and request.args.get('arn'):\n        response = {\n            'TagList': [\n                {\n                    'Key': 'Example1',\n                    'Value': 'Value'\n                },\n                {\n                    'Key': 'Example2',\n                    'Value': 'Value'\n                }\n            ]\n        }\n        return jsonify(response)\n\n    return jsonify({})\n\n\ndef serve(port, quiet=True):\n    generic_proxy.serve_flask_app(app=app, port=port, quiet=quiet)\n", "path": "localstack/services/es/es_api.py"}]}