localstack-core 4.7.1.dev49__py3-none-any.whl → 4.10.1.dev12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. localstack/aws/api/cloudformation/__init__.py +18 -4
  2. localstack/aws/api/cloudwatch/__init__.py +41 -1
  3. localstack/aws/api/config/__init__.py +4 -0
  4. localstack/aws/api/core.py +6 -2
  5. localstack/aws/api/dynamodb/__init__.py +30 -0
  6. localstack/aws/api/ec2/__init__.py +1522 -65
  7. localstack/aws/api/iam/__init__.py +7 -0
  8. localstack/aws/api/kinesis/__init__.py +19 -0
  9. localstack/aws/api/kms/__init__.py +6 -0
  10. localstack/aws/api/lambda_/__init__.py +13 -0
  11. localstack/aws/api/logs/__init__.py +15 -0
  12. localstack/aws/api/redshift/__init__.py +9 -3
  13. localstack/aws/api/route53/__init__.py +5 -0
  14. localstack/aws/api/s3/__init__.py +12 -0
  15. localstack/aws/api/s3control/__init__.py +54 -0
  16. localstack/aws/api/ssm/__init__.py +2 -0
  17. localstack/aws/api/transcribe/__init__.py +17 -0
  18. localstack/aws/client.py +7 -2
  19. localstack/aws/forwarder.py +52 -5
  20. localstack/aws/handlers/analytics.py +1 -1
  21. localstack/aws/handlers/internal_requests.py +6 -1
  22. localstack/aws/handlers/logging.py +12 -2
  23. localstack/aws/handlers/metric_handler.py +41 -1
  24. localstack/aws/handlers/service.py +40 -20
  25. localstack/aws/mocking.py +2 -2
  26. localstack/aws/patches.py +2 -2
  27. localstack/aws/protocol/parser.py +459 -32
  28. localstack/aws/protocol/serializer.py +689 -69
  29. localstack/aws/protocol/service_router.py +120 -20
  30. localstack/aws/protocol/validate.py +1 -1
  31. localstack/aws/scaffold.py +1 -1
  32. localstack/aws/skeleton.py +4 -2
  33. localstack/aws/spec-patches.json +58 -0
  34. localstack/aws/spec.py +37 -16
  35. localstack/cli/exceptions.py +1 -1
  36. localstack/cli/localstack.py +6 -6
  37. localstack/cli/lpm.py +3 -4
  38. localstack/cli/plugins.py +1 -1
  39. localstack/cli/profiles.py +1 -2
  40. localstack/config.py +25 -18
  41. localstack/constants.py +4 -29
  42. localstack/dev/kubernetes/__main__.py +130 -7
  43. localstack/dev/run/configurators.py +1 -4
  44. localstack/dev/run/paths.py +1 -1
  45. localstack/dns/plugins.py +5 -1
  46. localstack/dns/server.py +13 -4
  47. localstack/logging/format.py +3 -3
  48. localstack/packages/api.py +9 -8
  49. localstack/packages/core.py +2 -2
  50. localstack/packages/plugins.py +0 -8
  51. localstack/runtime/analytics.py +3 -0
  52. localstack/runtime/hooks.py +1 -1
  53. localstack/runtime/init.py +2 -2
  54. localstack/runtime/main.py +5 -5
  55. localstack/runtime/patches.py +2 -2
  56. localstack/services/apigateway/helpers.py +1 -4
  57. localstack/services/apigateway/legacy/helpers.py +7 -8
  58. localstack/services/apigateway/legacy/integration.py +4 -3
  59. localstack/services/apigateway/legacy/invocations.py +6 -5
  60. localstack/services/apigateway/legacy/provider.py +148 -68
  61. localstack/services/apigateway/legacy/templates.py +1 -1
  62. localstack/services/apigateway/next_gen/execute_api/handlers/method_request.py +7 -2
  63. localstack/services/apigateway/next_gen/execute_api/handlers/resource_router.py +1 -2
  64. localstack/services/apigateway/next_gen/execute_api/integrations/aws.py +3 -0
  65. localstack/services/apigateway/next_gen/execute_api/integrations/http.py +3 -3
  66. localstack/services/apigateway/next_gen/execute_api/template_mapping.py +2 -2
  67. localstack/services/apigateway/next_gen/execute_api/test_invoke.py +114 -9
  68. localstack/services/apigateway/next_gen/provider.py +5 -0
  69. localstack/services/apigateway/resource_providers/aws_apigateway_resource.py +1 -1
  70. localstack/services/cloudformation/api_utils.py +4 -8
  71. localstack/services/cloudformation/cfn_utils.py +1 -1
  72. localstack/services/cloudformation/engine/entities.py +14 -4
  73. localstack/services/cloudformation/engine/template_deployer.py +6 -4
  74. localstack/services/cloudformation/engine/transformers.py +6 -4
  75. localstack/services/cloudformation/engine/v2/change_set_model.py +201 -13
  76. localstack/services/cloudformation/engine/v2/change_set_model_describer.py +52 -3
  77. localstack/services/cloudformation/engine/v2/change_set_model_executor.py +117 -76
  78. localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +205 -52
  79. localstack/services/cloudformation/engine/v2/change_set_model_transform.py +350 -116
  80. localstack/services/cloudformation/engine/v2/change_set_model_validator.py +56 -14
  81. localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +1 -0
  82. localstack/services/cloudformation/engine/v2/resolving.py +7 -5
  83. localstack/services/cloudformation/engine/yaml_parser.py +9 -2
  84. localstack/services/cloudformation/provider.py +7 -5
  85. localstack/services/cloudformation/resource_provider.py +7 -1
  86. localstack/services/cloudformation/resources.py +24149 -0
  87. localstack/services/cloudformation/service_models.py +2 -2
  88. localstack/services/cloudformation/v2/entities.py +19 -9
  89. localstack/services/cloudformation/v2/provider.py +336 -106
  90. localstack/services/cloudformation/v2/types.py +13 -7
  91. localstack/services/cloudformation/v2/utils.py +4 -1
  92. localstack/services/cloudwatch/alarm_scheduler.py +4 -1
  93. localstack/services/cloudwatch/provider.py +18 -13
  94. localstack/services/cloudwatch/provider_v2.py +25 -28
  95. localstack/services/dynamodb/packages.py +2 -1
  96. localstack/services/dynamodb/provider.py +42 -0
  97. localstack/services/dynamodb/server.py +2 -2
  98. localstack/services/dynamodb/v2/provider.py +42 -0
  99. localstack/services/ecr/resource_providers/aws_ecr_repository.py +5 -2
  100. localstack/services/edge.py +1 -1
  101. localstack/services/es/provider.py +2 -2
  102. localstack/services/events/event_rule_engine.py +31 -13
  103. localstack/services/events/models.py +4 -5
  104. localstack/services/events/provider.py +17 -14
  105. localstack/services/events/target.py +17 -9
  106. localstack/services/events/v1/provider.py +5 -5
  107. localstack/services/firehose/provider.py +14 -4
  108. localstack/services/iam/provider.py +11 -116
  109. localstack/services/iam/resources/policy_simulator.py +133 -0
  110. localstack/services/kinesis/models.py +15 -2
  111. localstack/services/kinesis/provider.py +86 -3
  112. localstack/services/kms/provider.py +14 -5
  113. localstack/services/lambda_/api_utils.py +6 -3
  114. localstack/services/lambda_/invocation/docker_runtime_executor.py +1 -1
  115. localstack/services/lambda_/invocation/event_manager.py +1 -1
  116. localstack/services/lambda_/invocation/internal_sqs_queue.py +5 -9
  117. localstack/services/lambda_/invocation/lambda_models.py +10 -7
  118. localstack/services/lambda_/invocation/lambda_service.py +5 -1
  119. localstack/services/lambda_/packages.py +1 -1
  120. localstack/services/lambda_/provider.py +4 -3
  121. localstack/services/lambda_/provider_utils.py +1 -1
  122. localstack/services/logs/provider.py +36 -19
  123. localstack/services/moto.py +2 -1
  124. localstack/services/opensearch/cluster.py +15 -7
  125. localstack/services/opensearch/packages.py +26 -7
  126. localstack/services/opensearch/provider.py +8 -2
  127. localstack/services/opensearch/versions.py +56 -7
  128. localstack/services/plugins.py +11 -7
  129. localstack/services/providers.py +10 -2
  130. localstack/services/redshift/provider.py +0 -21
  131. localstack/services/s3/constants.py +5 -2
  132. localstack/services/s3/cors.py +4 -4
  133. localstack/services/s3/models.py +1 -1
  134. localstack/services/s3/notifications.py +55 -39
  135. localstack/services/s3/presigned_url.py +35 -54
  136. localstack/services/s3/provider.py +73 -15
  137. localstack/services/s3/utils.py +42 -22
  138. localstack/services/s3/validation.py +46 -32
  139. localstack/services/s3/website_hosting.py +4 -2
  140. localstack/services/ses/provider.py +18 -8
  141. localstack/services/sns/constants.py +7 -1
  142. localstack/services/sns/executor.py +9 -2
  143. localstack/services/sns/provider.py +8 -5
  144. localstack/services/sns/publisher.py +31 -16
  145. localstack/services/sns/v2/models.py +167 -0
  146. localstack/services/sns/v2/provider.py +867 -0
  147. localstack/services/sns/v2/utils.py +130 -0
  148. localstack/services/sqs/constants.py +1 -1
  149. localstack/services/sqs/developer_api.py +205 -0
  150. localstack/services/sqs/models.py +48 -5
  151. localstack/services/sqs/provider.py +38 -311
  152. localstack/services/sqs/query_api.py +6 -2
  153. localstack/services/sqs/utils.py +121 -2
  154. localstack/services/ssm/provider.py +1 -1
  155. localstack/services/stepfunctions/asl/component/intrinsic/member.py +1 -1
  156. localstack/services/stepfunctions/asl/component/state/state_choice/comparison/comparison.py +5 -11
  157. localstack/services/stepfunctions/asl/component/state/state_choice/state_choice.py +2 -2
  158. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py +2 -2
  159. localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/state_parallel.py +1 -1
  160. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task.py +2 -2
  161. localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py +1 -1
  162. localstack/services/stepfunctions/asl/component/state/state_pass/state_pass.py +2 -2
  163. localstack/services/stepfunctions/asl/component/state/state_succeed/state_succeed.py +1 -1
  164. localstack/services/stepfunctions/asl/component/state/state_wait/state_wait.py +1 -1
  165. localstack/services/stepfunctions/asl/eval/environment.py +1 -1
  166. localstack/services/stepfunctions/asl/jsonata/jsonata.py +1 -1
  167. localstack/services/stepfunctions/backend/execution.py +2 -1
  168. localstack/services/stores.py +1 -1
  169. localstack/services/transcribe/provider.py +6 -1
  170. localstack/state/codecs.py +61 -0
  171. localstack/state/core.py +11 -5
  172. localstack/state/pickle.py +10 -49
  173. localstack/testing/aws/cloudformation_utils.py +1 -1
  174. localstack/testing/pytest/cloudformation/fixtures.py +3 -3
  175. localstack/testing/pytest/cloudformation/transformers.py +0 -0
  176. localstack/testing/pytest/container.py +4 -5
  177. localstack/testing/pytest/fixtures.py +33 -31
  178. localstack/testing/pytest/in_memory_localstack.py +0 -4
  179. localstack/testing/pytest/marking.py +38 -11
  180. localstack/testing/pytest/stepfunctions/utils.py +4 -3
  181. localstack/testing/pytest/util.py +1 -1
  182. localstack/testing/pytest/validation_tracking.py +1 -2
  183. localstack/testing/snapshots/transformer_utility.py +6 -1
  184. localstack/utils/analytics/events.py +2 -2
  185. localstack/utils/analytics/metadata.py +6 -4
  186. localstack/utils/analytics/metrics/counter.py +8 -15
  187. localstack/utils/analytics/publisher.py +1 -2
  188. localstack/utils/analytics/service_providers.py +19 -0
  189. localstack/utils/analytics/service_request_aggregator.py +2 -2
  190. localstack/utils/archives.py +11 -11
  191. localstack/utils/asyncio.py +2 -2
  192. localstack/utils/aws/arns.py +24 -29
  193. localstack/utils/aws/aws_responses.py +8 -8
  194. localstack/utils/aws/aws_stack.py +2 -3
  195. localstack/utils/aws/dead_letter_queue.py +1 -5
  196. localstack/utils/aws/message_forwarding.py +1 -2
  197. localstack/utils/aws/request_context.py +4 -5
  198. localstack/utils/aws/resources.py +1 -1
  199. localstack/utils/aws/templating.py +1 -1
  200. localstack/utils/batch_policy.py +3 -3
  201. localstack/utils/bootstrap.py +21 -13
  202. localstack/utils/catalog/catalog.py +139 -0
  203. localstack/utils/catalog/catalog_loader.py +119 -0
  204. localstack/utils/catalog/common.py +58 -0
  205. localstack/utils/catalog/plugins.py +28 -0
  206. localstack/utils/cloudwatch/cloudwatch_util.py +5 -5
  207. localstack/utils/collections.py +7 -8
  208. localstack/utils/config_listener.py +1 -1
  209. localstack/utils/container_networking.py +2 -3
  210. localstack/utils/container_utils/container_client.py +135 -136
  211. localstack/utils/container_utils/docker_cmd_client.py +85 -69
  212. localstack/utils/container_utils/docker_sdk_client.py +69 -66
  213. localstack/utils/crypto.py +10 -10
  214. localstack/utils/diagnose.py +3 -4
  215. localstack/utils/docker_utils.py +9 -5
  216. localstack/utils/files.py +33 -13
  217. localstack/utils/functions.py +4 -3
  218. localstack/utils/http.py +11 -11
  219. localstack/utils/json.py +20 -6
  220. localstack/utils/kinesis/kinesis_connector.py +2 -1
  221. localstack/utils/net.py +15 -9
  222. localstack/utils/no_exit_argument_parser.py +2 -2
  223. localstack/utils/numbers.py +9 -2
  224. localstack/utils/objects.py +7 -6
  225. localstack/utils/patch.py +10 -3
  226. localstack/utils/run.py +12 -11
  227. localstack/utils/scheduler.py +11 -11
  228. localstack/utils/server/tcp_proxy.py +2 -2
  229. localstack/utils/serving.py +3 -4
  230. localstack/utils/strings.py +15 -16
  231. localstack/utils/sync.py +126 -1
  232. localstack/utils/tagging.py +8 -6
  233. localstack/utils/testutil.py +8 -8
  234. localstack/utils/threads.py +2 -2
  235. localstack/utils/time.py +12 -4
  236. localstack/utils/urls.py +1 -3
  237. localstack/utils/xray/traceid.py +1 -1
  238. localstack/version.py +16 -3
  239. {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/METADATA +18 -14
  240. {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/RECORD +248 -239
  241. {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/entry_points.txt +8 -4
  242. localstack_core-4.10.1.dev12.dist-info/plux.json +1 -0
  243. localstack/packages/terraform.py +0 -46
  244. localstack/services/cloudformation/deploy.html +0 -144
  245. localstack/services/cloudformation/deploy_ui.py +0 -47
  246. localstack/services/cloudformation/plugins.py +0 -12
  247. localstack_core-4.7.1.dev49.dist-info/plux.json +0 -1
  248. {localstack_core-4.7.1.dev49.data → localstack_core-4.10.1.dev12.data}/scripts/localstack +0 -0
  249. {localstack_core-4.7.1.dev49.data → localstack_core-4.10.1.dev12.data}/scripts/localstack-supervisor +0 -0
  250. {localstack_core-4.7.1.dev49.data → localstack_core-4.10.1.dev12.data}/scripts/localstack.bat +0 -0
  251. {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/WHEEL +0 -0
  252. {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/licenses/LICENSE.txt +0 -0
  253. {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,7 @@
1
+ import json
1
2
  import logging
2
3
  import os
4
+ import re
3
5
  import time
4
6
  from random import random
5
7
 
@@ -8,14 +10,18 @@ from localstack.aws.api import RequestContext
8
10
  from localstack.aws.api.kinesis import (
9
11
  ConsumerARN,
10
12
  Data,
13
+ GetResourcePolicyOutput,
11
14
  HashKey,
12
15
  KinesisApi,
13
16
  PartitionKey,
17
+ Policy,
14
18
  ProvisionedThroughputExceededException,
15
19
  PutRecordOutput,
16
20
  PutRecordsOutput,
17
21
  PutRecordsRequestEntryList,
18
22
  PutRecordsResultEntry,
23
+ ResourceARN,
24
+ ResourceNotFoundException,
19
25
  SequenceNumber,
20
26
  ShardId,
21
27
  StartingPosition,
@@ -24,6 +30,7 @@ from localstack.aws.api.kinesis import (
24
30
  SubscribeToShardEvent,
25
31
  SubscribeToShardEventStream,
26
32
  SubscribeToShardOutput,
33
+ ValidationException,
27
34
  )
28
35
  from localstack.aws.connect import connect_to
29
36
  from localstack.constants import LOCALHOST
@@ -39,6 +46,13 @@ LOG = logging.getLogger(__name__)
39
46
  MAX_SUBSCRIPTION_SECONDS = 300
40
47
  SERVER_STARTUP_TIMEOUT = 120
41
48
 
49
+ DATA_STREAM_ARN_REGEX = re.compile(
50
+ r"^arn:aws(?:-[a-z]+)*:kinesis:[a-z0-9-]+:\d{12}:stream\/[a-zA-Z0-9_.\-]+$"
51
+ )
52
+ CONSUMER_ARN_REGEX = re.compile(
53
+ r"^arn:aws(?:-[a-z]+)*:kinesis:[a-z0-9-]+:\d{12}:stream\/[a-zA-Z0-9_.\-]+\/consumer\/[a-zA-Z0-9_.\-]+:\d+$"
54
+ )
55
+
42
56
 
43
57
  def find_stream_for_consumer(consumer_arn):
44
58
  account_id = extract_account_id_from_arn(consumer_arn)
@@ -49,7 +63,12 @@ def find_stream_for_consumer(consumer_arn):
49
63
  for cons in kinesis.list_stream_consumers(StreamARN=stream_arn)["Consumers"]:
50
64
  if cons["ConsumerARN"] == consumer_arn:
51
65
  return stream_name
52
- raise Exception("Unable to find stream for stream consumer %s" % consumer_arn)
66
+ raise Exception(f"Unable to find stream for stream consumer {consumer_arn}")
67
+
68
+
69
+ def is_valid_kinesis_arn(resource_arn: ResourceARN) -> bool:
70
+ """Check if the provided ARN is a valid Kinesis ARN."""
71
+ return bool(CONSUMER_ARN_REGEX.match(resource_arn) or DATA_STREAM_ARN_REGEX.match(resource_arn))
53
72
 
54
73
 
55
74
  class KinesisProvider(KinesisApi, ServiceLifecycleHook):
@@ -81,6 +100,64 @@ class KinesisProvider(KinesisApi, ServiceLifecycleHook):
81
100
  def get_store(account_id: str, region_name: str) -> KinesisStore:
82
101
  return kinesis_stores[account_id][region_name]
83
102
 
103
+ def put_resource_policy(
104
+ self,
105
+ context: RequestContext,
106
+ resource_arn: ResourceARN,
107
+ policy: Policy,
108
+ **kwargs,
109
+ ) -> None:
110
+ if not is_valid_kinesis_arn(resource_arn):
111
+ raise ValidationException(f"invalid kinesis arn {resource_arn}")
112
+
113
+ kinesis = connect_to(
114
+ aws_access_key_id=context.account_id, region_name=context.region
115
+ ).kinesis
116
+ try:
117
+ kinesis.describe_stream_summary(StreamARN=resource_arn)
118
+ except kinesis.exceptions.ResourceNotFoundException:
119
+ raise ResourceNotFoundException(f"Stream with ARN {resource_arn} not found")
120
+
121
+ store = self.get_store(context.account_id, context.region)
122
+ store.resource_policies[resource_arn] = policy
123
+
124
+ def get_resource_policy(
125
+ self,
126
+ context: RequestContext,
127
+ resource_arn: ResourceARN,
128
+ **kwargs,
129
+ ) -> GetResourcePolicyOutput:
130
+ if not is_valid_kinesis_arn(resource_arn):
131
+ raise ValidationException(f"invalid kinesis arn {resource_arn}")
132
+
133
+ kinesis = connect_to(
134
+ aws_access_key_id=context.account_id, region_name=context.region
135
+ ).kinesis
136
+ try:
137
+ kinesis.describe_stream_summary(StreamARN=resource_arn)
138
+ except kinesis.exceptions.ResourceNotFoundException:
139
+ raise ResourceNotFoundException(f"Stream with ARN {resource_arn} not found")
140
+
141
+ store = self.get_store(context.account_id, context.region)
142
+ policy = store.resource_policies.get(resource_arn, json.dumps({}))
143
+ return GetResourcePolicyOutput(Policy=policy)
144
+
145
+ def delete_resource_policy(
146
+ self,
147
+ context: RequestContext,
148
+ resource_arn: ResourceARN,
149
+ **kwargs,
150
+ ) -> None:
151
+ if not is_valid_kinesis_arn(resource_arn):
152
+ raise ValidationException(f"invalid kinesis arn {resource_arn}")
153
+
154
+ store = self.get_store(context.account_id, context.region)
155
+ if resource_arn not in store.resource_policies:
156
+ raise ResourceNotFoundException(
157
+ f"No resource policy found for resource ARN {resource_arn}"
158
+ )
159
+ del store.resource_policies[resource_arn]
160
+
84
161
  def subscribe_to_shard(
85
162
  self,
86
163
  context: RequestContext,
@@ -125,7 +202,13 @@ class KinesisProvider(KinesisApi, ServiceLifecycleHook):
125
202
  raise
126
203
  shard_iterator = result.get("NextShardIterator")
127
204
  records = result.get("Records", [])
128
- if not records:
205
+ if records:
206
+ # Update the last sequence number to the last record's sequence number
207
+ # TODO: This will suffice for now but does not properly capture checkpointing when
208
+ # no data is written to a shard. See AWS docs:
209
+ # https://docs.aws.amazon.com/kinesis/latest/APIReference/API_SubscribeToShardEvent.html#API_SubscribeToShardEvent_Contents
210
+ last_sequence_number = records[-1].get("SequenceNumber", last_sequence_number)
211
+ else:
129
212
  # On AWS there is *at least* 1 event every 5 seconds
130
213
  # but this is not possible in this structure.
131
214
  # In order to avoid a 5-second blocking call, we make the compromise of 3 seconds.
@@ -136,7 +219,7 @@ class KinesisProvider(KinesisApi, ServiceLifecycleHook):
136
219
  Records=records,
137
220
  ContinuationSequenceNumber=str(last_sequence_number),
138
221
  MillisBehindLatest=0,
139
- ChildShards=[],
222
+ ChildShards=None, # TODO: Include shard children info
140
223
  )
141
224
  )
142
225
 
@@ -85,6 +85,7 @@ from localstack.aws.api.kms import (
85
85
  MacAlgorithmSpec,
86
86
  MarkerType,
87
87
  MultiRegionKey,
88
+ MultiRegionKeyType,
88
89
  NotFoundException,
89
90
  NullableBooleanType,
90
91
  OriginType,
@@ -490,24 +491,32 @@ class KmsProvider(KmsApi, ServiceLifecycleHook):
490
491
  self, context: RequestContext, request: ReplicateKeyRequest
491
492
  ) -> ReplicateKeyResponse:
492
493
  account_id = context.account_id
493
- key = self._get_kms_key(account_id, context.region, request.get("KeyId"))
494
- key_id = key.metadata.get("KeyId")
495
- if not key.metadata.get("MultiRegion"):
494
+ primary_key = self._get_kms_key(account_id, context.region, request.get("KeyId"))
495
+ key_id = primary_key.metadata.get("KeyId")
496
+ key_arn = primary_key.metadata.get("Arn")
497
+ if not primary_key.metadata.get("MultiRegion"):
496
498
  raise UnsupportedOperationException(
497
499
  f"Unable to replicate a non-MultiRegion key {key_id}"
498
500
  )
499
501
  replica_region = request.get("ReplicaRegion")
500
502
  replicate_to_store = kms_stores[account_id][replica_region]
503
+
504
+ if (
505
+ primary_key.metadata.get("MultiRegionConfiguration", {}).get("MultiRegionKeyType")
506
+ != MultiRegionKeyType.PRIMARY
507
+ ):
508
+ raise UnsupportedOperationException(f"{key_arn} is not a multi-region primary key.")
509
+
501
510
  if key_id in replicate_to_store.keys:
502
511
  raise AlreadyExistsException(
503
512
  f"Unable to replicate key {key_id} to region {replica_region}, as the key "
504
513
  f"already exist there"
505
514
  )
506
- replica_key = copy.deepcopy(key)
515
+ replica_key = copy.deepcopy(primary_key)
507
516
  replica_key.replicate_metadata(request, account_id, replica_region)
508
517
  replicate_to_store.keys[key_id] = replica_key
509
518
 
510
- self.update_primary_key_with_replica_keys(key, replica_key, replica_region)
519
+ self.update_primary_key_with_replica_keys(primary_key, replica_key, replica_region)
511
520
 
512
521
  return ReplicateKeyResponse(ReplicaKeyMetadata=replica_key.metadata)
513
522
 
@@ -8,6 +8,7 @@ import re
8
8
  import string
9
9
  from typing import TYPE_CHECKING, Any
10
10
 
11
+ from localstack import config
11
12
  from localstack.aws.api import CommonServiceException, RequestContext
12
13
  from localstack.aws.api import lambda_ as api_spec
13
14
  from localstack.aws.api.lambda_ import (
@@ -665,7 +666,9 @@ def validate_and_set_batch_size(service: str, batch_size: int | None = None) ->
665
666
  def map_layer_out(layer_version: "LayerVersion") -> PublishLayerVersionResponse:
666
667
  return PublishLayerVersionResponse(
667
668
  Content=LayerVersionContentOutput(
668
- Location=layer_version.code.generate_presigned_url(),
669
+ Location=layer_version.code.generate_presigned_url(
670
+ endpoint_url=config.external_service_url()
671
+ ),
669
672
  CodeSha256=layer_version.code.code_sha256,
670
673
  CodeSize=layer_version.code.code_size,
671
674
  # SigningProfileVersionArn="", # same as in function configuration
@@ -715,12 +718,12 @@ def validate_layer_runtimes_and_architectures(
715
718
 
716
719
  if compatible_runtimes and set(compatible_runtimes).difference(ALL_RUNTIMES):
717
720
  constraint = f"Member must satisfy enum value set: {VALID_RUNTIMES}"
718
- validation_msg = f"Value '[{', '.join([s for s in compatible_runtimes])}]' at 'compatibleRuntimes' failed to satisfy constraint: {constraint}"
721
+ validation_msg = f"Value '[{', '.join(list(compatible_runtimes))}]' at 'compatibleRuntimes' failed to satisfy constraint: {constraint}"
719
722
  validations.append(validation_msg)
720
723
 
721
724
  if compatible_architectures and set(compatible_architectures).difference(ARCHITECTURES):
722
725
  constraint = "[Member must satisfy enum value set: [x86_64, arm64]]"
723
- validation_msg = f"Value '[{', '.join([s for s in compatible_architectures])}]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: {constraint}"
726
+ validation_msg = f"Value '[{', '.join(list(compatible_architectures))}]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: {constraint}"
724
727
  validations.append(validation_msg)
725
728
 
726
729
  return validations
@@ -280,7 +280,7 @@ class DockerRuntimeExecutor(RuntimeExecutor):
280
280
  container_name: str
281
281
 
282
282
  def __init__(self, id: str, function_version: FunctionVersion) -> None:
283
- super(DockerRuntimeExecutor, self).__init__(id=id, function_version=function_version)
283
+ super().__init__(id=id, function_version=function_version)
284
284
  self.ip = None
285
285
  self.executor_endpoint = ExecutorEndpoint(self.id)
286
286
  self.container_name = self._generate_container_name()
@@ -42,7 +42,7 @@ def get_sqs_client(function_version: FunctionVersion, client_config=None):
42
42
  # TODO: remove once DLQ handling is refactored following the removal of the legacy lambda provider
43
43
  class LegacyInvocationException(Exception):
44
44
  def __init__(self, message, log_output=None, result=None):
45
- super(LegacyInvocationException, self).__init__(message)
45
+ super().__init__(message)
46
46
  self.log_output = log_output
47
47
  self.result = result
48
48
 
@@ -19,13 +19,9 @@ from localstack.aws.api.sqs import (
19
19
  String,
20
20
  TagMap,
21
21
  )
22
- from localstack.services.sqs.models import SqsQueue, StandardQueue
23
- from localstack.services.sqs.provider import (
24
- QueueUpdateWorker,
25
- _create_message_attribute_hash,
26
- to_sqs_api_message,
27
- )
28
- from localstack.services.sqs.utils import generate_message_id
22
+ from localstack.services.sqs.models import SqsQueue, StandardQueue, to_sqs_api_message
23
+ from localstack.services.sqs.provider import QueueUpdateWorker
24
+ from localstack.services.sqs.utils import create_message_attribute_hash, generate_message_id
29
25
  from localstack.utils.objects import singleton_factory
30
26
  from localstack.utils.strings import md5
31
27
  from localstack.utils.time import now
@@ -189,7 +185,7 @@ class FakeSqsClient:
189
185
  MD5OfBody=md5(MessageBody),
190
186
  Body=MessageBody,
191
187
  Attributes=self._create_message_attributes(MessageSystemAttributes),
192
- MD5OfMessageAttributes=_create_message_attribute_hash(MessageAttributes),
188
+ MD5OfMessageAttributes=create_message_attribute_hash(MessageAttributes),
193
189
  MessageAttributes=MessageAttributes,
194
190
  )
195
191
  queue_item = queue.put(
@@ -204,7 +200,7 @@ class FakeSqsClient:
204
200
  "MD5OfMessageBody": message["MD5OfBody"],
205
201
  "MD5OfMessageAttributes": message.get("MD5OfMessageAttributes"),
206
202
  "SequenceNumber": queue_item.sequence_number,
207
- "MD5OfMessageSystemAttributes": _create_message_attribute_hash(MessageSystemAttributes),
203
+ "MD5OfMessageSystemAttributes": create_message_attribute_hash(MessageSystemAttributes),
208
204
  }
209
205
 
210
206
 
@@ -14,6 +14,7 @@ from datetime import datetime
14
14
  from pathlib import Path
15
15
  from typing import IO, Literal, TypedDict
16
16
 
17
+ import boto3
17
18
  from botocore.exceptions import ClientError
18
19
 
19
20
  from localstack import config
@@ -40,7 +41,7 @@ from localstack.aws.api.lambda_ import (
40
41
  TracingMode,
41
42
  )
42
43
  from localstack.aws.connect import connect_to
43
- from localstack.constants import AWS_REGION_US_EAST_1
44
+ from localstack.constants import AWS_REGION_US_EAST_1, INTERNAL_AWS_SECRET_ACCESS_KEY
44
45
  from localstack.services.lambda_.api_utils import qualified_lambda_arn, unqualified_lambda_arn
45
46
  from localstack.utils.archives import unzip
46
47
  from localstack.utils.strings import long_uid, short_uid
@@ -74,7 +75,7 @@ InitializationType = Literal["on-demand", "provisioned-concurrency"]
74
75
 
75
76
  class ArchiveCode(metaclass=ABCMeta):
76
77
  @abstractmethod
77
- def generate_presigned_url(self, endpoint_url: str | None = None):
78
+ def generate_presigned_url(self, endpoint_url: str):
78
79
  """
79
80
  Generates a presigned url pointing to the code archive
80
81
  """
@@ -168,15 +169,17 @@ class S3Code(ArchiveCode):
168
169
  )
169
170
  target_file.flush()
170
171
 
171
- def generate_presigned_url(self, endpoint_url: str | None = None) -> str:
172
+ def generate_presigned_url(self, endpoint_url: str) -> str:
172
173
  """
173
174
  Generates a presigned url pointing to the code archive
174
175
  """
175
- s3_client = connect_to(
176
+ s3_client = boto3.client(
177
+ "s3",
176
178
  region_name=AWS_REGION_US_EAST_1,
177
179
  aws_access_key_id=config.INTERNAL_RESOURCE_ACCOUNT,
180
+ aws_secret_access_key=INTERNAL_AWS_SECRET_ACCESS_KEY,
178
181
  endpoint_url=endpoint_url,
179
- ).s3
182
+ )
180
183
  params = {"Bucket": self.s3_bucket, "Key": self.s3_key}
181
184
  if self.s3_object_version:
182
185
  params["VersionId"] = self.s3_object_version
@@ -257,8 +260,8 @@ class HotReloadingCode(ArchiveCode):
257
260
  code_sha256: str = "hot-reloading-hash-not-available"
258
261
  code_size: int = 0
259
262
 
260
- def generate_presigned_url(self, endpoint_url: str | None = None) -> str:
261
- return f"Code location: {self.host_path}"
263
+ def generate_presigned_url(self, endpoint_url: str) -> str:
264
+ return f"file://{self.host_path}"
262
265
 
263
266
  def get_unzipped_code_location(self) -> Path:
264
267
  path = os.path.expandvars(self.host_path)
@@ -478,7 +478,11 @@ class LambdaService:
478
478
  ] = new_version_state
479
479
 
480
480
  except Exception:
481
- LOG.exception("Failed to update function version for arn %s", function_arn)
481
+ LOG.error(
482
+ "Failed to update function version for arn %s",
483
+ function_arn,
484
+ exc_info=LOG.isEnabledFor(logging.DEBUG),
485
+ )
482
486
 
483
487
  def update_alias(self, old_alias: VersionAlias, new_alias: VersionAlias, function: Function):
484
488
  # if pointer changed, need to restart provisioned
@@ -12,7 +12,7 @@ from localstack.utils.platform import get_arch
12
12
  """Customized LocalStack version of the AWS Lambda Runtime Interface Emulator (RIE).
13
13
  https://github.com/localstack/lambda-runtime-init/blob/localstack/README-LOCALSTACK.md
14
14
  """
15
- LAMBDA_RUNTIME_DEFAULT_VERSION = "v0.1.34-pre"
15
+ LAMBDA_RUNTIME_DEFAULT_VERSION = "v0.1.36-pre"
16
16
  LAMBDA_RUNTIME_VERSION = config.LAMBDA_INIT_RELEASE_VERSION or LAMBDA_RUNTIME_DEFAULT_VERSION
17
17
  LAMBDA_RUNTIME_INIT_URL = "https://github.com/localstack/lambda-runtime-init/releases/download/{version}/aws-lambda-rie-{arch}"
18
18
 
@@ -313,7 +313,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
313
313
  LOG.warning(
314
314
  "Failed to restore function version %s",
315
315
  fn_version.id.qualified_arn(),
316
- exc_info=True,
316
+ exc_info=LOG.isEnabledFor(logging.DEBUG),
317
317
  )
318
318
  # restore provisioned concurrency per function considering both versions and aliases
319
319
  for (
@@ -344,7 +344,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
344
344
  "Failed to restore provisioned concurrency %s for function %s",
345
345
  provisioned_config,
346
346
  fn_arn,
347
- exc_info=True,
347
+ exc_info=LOG.isEnabledFor(logging.DEBUG),
348
348
  )
349
349
 
350
350
  for esm in state.event_source_mappings.values():
@@ -1512,7 +1512,8 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1512
1512
  code_location = None
1513
1513
  if code := version.config.code:
1514
1514
  code_location = FunctionCodeLocation(
1515
- Location=code.generate_presigned_url(), RepositoryType="S3"
1515
+ Location=code.generate_presigned_url(endpoint_url=config.external_service_url()),
1516
+ RepositoryType="S3",
1516
1517
  )
1517
1518
  elif image := version.config.image:
1518
1519
  code_location = FunctionCodeLocation(
@@ -74,7 +74,7 @@ class LambdaLayerVersionIdentifier(ResourceIdentifier):
74
74
  resource = "layer-version"
75
75
 
76
76
  def __init__(self, account_id: str, region: str, layer_name: str):
77
- super(LambdaLayerVersionIdentifier, self).__init__(account_id, region, layer_name)
77
+ super().__init__(account_id, region, layer_name)
78
78
 
79
79
  def generate(
80
80
  self, existing_ids: ExistingIds = None, tags: Tags = None, next_version: int = None
@@ -22,10 +22,13 @@ from localstack.aws.api.logs import (
22
22
  InputLogEvents,
23
23
  InvalidParameterException,
24
24
  KmsKeyId,
25
+ ListLogGroupsRequest,
26
+ ListLogGroupsResponse,
25
27
  ListTagsForResourceResponse,
26
28
  ListTagsLogGroupResponse,
27
29
  LogGroupClass,
28
30
  LogGroupName,
31
+ LogGroupSummary,
29
32
  LogsApi,
30
33
  LogStreamName,
31
34
  PutLogEventsResponse,
@@ -43,7 +46,7 @@ from localstack.services.plugins import ServiceLifecycleHook
43
46
  from localstack.utils.aws import arns
44
47
  from localstack.utils.aws.client_types import ServicePrincipal
45
48
  from localstack.utils.bootstrap import is_api_enabled
46
- from localstack.utils.common import is_number
49
+ from localstack.utils.numbers import is_number
47
50
  from localstack.utils.patch import patch
48
51
 
49
52
  LOG = logging.getLogger(__name__)
@@ -60,8 +63,8 @@ class LogsProvider(LogsApi, ServiceLifecycleHook):
60
63
  log_group_name: LogGroupName,
61
64
  log_stream_name: LogStreamName,
62
65
  log_events: InputLogEvents,
63
- sequence_token: SequenceToken = None,
64
- entity: Entity = None,
66
+ sequence_token: SequenceToken | None = None,
67
+ entity: Entity | None = None,
65
68
  **kwargs,
66
69
  ) -> PutLogEventsResponse:
67
70
  logs_backend = get_moto_logs_backend(context.account_id, context.region)
@@ -97,33 +100,32 @@ class LogsProvider(LogsApi, ServiceLifecycleHook):
97
100
  ) -> DescribeLogGroupsResponse:
98
101
  region_backend = get_moto_logs_backend(context.account_id, context.region)
99
102
 
100
- prefix: str = request.get("logGroupNamePrefix", "")
101
- pattern: str = request.get("logGroupNamePattern", "")
103
+ prefix: str | None = request.get("logGroupNamePrefix", "")
104
+ pattern: str | None = request.get("logGroupNamePattern", "")
102
105
 
103
106
  if pattern and prefix:
104
107
  raise InvalidParameterException(
105
108
  "LogGroup name prefix and LogGroup name pattern are mutually exclusive parameters."
106
109
  )
107
110
 
108
- copy_groups = copy.deepcopy(region_backend.groups)
111
+ moto_groups = copy.deepcopy(dict(region_backend.groups)).values()
109
112
 
110
113
  groups = [
111
- group.to_describe_dict()
112
- for name, group in copy_groups.items()
114
+ {"logGroupClass": LogGroupClass.STANDARD} | group.to_describe_dict()
115
+ for group in sorted(moto_groups, key=lambda g: g.name)
113
116
  if not (prefix or pattern)
114
- or (prefix and name.startswith(prefix))
115
- or (pattern and pattern in name)
117
+ or (prefix and group.name.startswith(prefix))
118
+ or (pattern and pattern in group.name)
116
119
  ]
117
120
 
118
- groups = sorted(groups, key=lambda x: x["logGroupName"])
119
121
  return DescribeLogGroupsResponse(logGroups=groups)
120
122
 
121
123
  @handler("DescribeLogStreams", expand=False)
122
124
  def describe_log_streams(
123
125
  self, context: RequestContext, request: DescribeLogStreamsRequest
124
126
  ) -> DescribeLogStreamsResponse:
125
- log_group_name: str = request.get("logGroupName")
126
- log_group_identifier: str = request.get("logGroupIdentifier")
127
+ log_group_name: str | None = request.get("logGroupName")
128
+ log_group_identifier: str | None = request.get("logGroupIdentifier")
127
129
 
128
130
  if log_group_identifier and log_group_name:
129
131
  raise CommonServiceException(
@@ -138,13 +140,29 @@ class LogsProvider(LogsApi, ServiceLifecycleHook):
138
140
 
139
141
  return moto.call_moto_with_request(context, request_copy)
140
142
 
143
+ @handler("ListLogGroups", expand=False)
144
+ def list_log_groups(
145
+ self, context: RequestContext, request: ListLogGroupsRequest
146
+ ) -> ListLogGroupsResponse:
147
+ pattern: str | None = request.get("logGroupNamePattern")
148
+ region_backend: LogsBackend = get_moto_logs_backend(context.account_id, context.region)
149
+ moto_groups = copy.deepcopy(region_backend.groups).values()
150
+ groups = [
151
+ LogGroupSummary(
152
+ logGroupName=group.name, logGroupArn=group.arn, logGroupClass=LogGroupClass.STANDARD
153
+ )
154
+ for group in sorted(moto_groups, key=lambda g: g.name)
155
+ if not pattern or pattern in group.name
156
+ ]
157
+ return ListLogGroupsResponse(logGroups=groups)
158
+
141
159
  def create_log_group(
142
160
  self,
143
161
  context: RequestContext,
144
162
  log_group_name: LogGroupName,
145
- kms_key_id: KmsKeyId = None,
146
- tags: Tags = None,
147
- log_group_class: LogGroupClass = None,
163
+ kms_key_id: KmsKeyId | None = None,
164
+ tags: Tags | None = None,
165
+ log_group_class: LogGroupClass | None = None,
148
166
  **kwargs,
149
167
  ) -> None:
150
168
  call_moto(context)
@@ -442,10 +460,9 @@ def moto_to_describe_dict(target, self):
442
460
  # reported race condition in https://github.com/localstack/localstack/issues/8011
443
461
  # making copy of "streams" dict here to avoid issues while summing up storedBytes
444
462
  copy_streams = copy.deepcopy(self.streams)
445
- # parity tests shows that the arn ends with ":*"
446
- arn = self.arn if self.arn.endswith(":*") else f"{self.arn}:*"
447
463
  log_group = {
448
- "arn": arn,
464
+ "arn": f"{self.arn}:*",
465
+ "logGroupArn": self.arn,
449
466
  "creationTime": self.creation_time,
450
467
  "logGroupName": self.name,
451
468
  "metricFilterCount": 0,
@@ -1,5 +1,5 @@
1
1
  """
2
- This module provides tools to call moto using moto and botocore internals without going through the moto HTTP server.
2
+ This module provides tools to call Moto service implementations.
3
3
  """
4
4
 
5
5
  import copy
@@ -65,6 +65,7 @@ def call_moto_with_request(
65
65
  action=context.operation.name,
66
66
  parameters=service_request,
67
67
  region=context.region,
68
+ protocol=context.protocol,
68
69
  )
69
70
  # we keep the headers from the original request, but override them with the ones created from the `service_request`
70
71
  headers = copy.deepcopy(context.request.headers)
@@ -18,7 +18,12 @@ from localstack.http.client import SimpleRequestsClient
18
18
  from localstack.http.proxy import ProxyHandler
19
19
  from localstack.services.edge import ROUTER
20
20
  from localstack.services.opensearch import versions
21
- from localstack.services.opensearch.packages import elasticsearch_package, opensearch_package
21
+ from localstack.services.opensearch.packages import (
22
+ ELASTICSEARCH_DEFAULT_VERSION,
23
+ OPENSEARCH_DEFAULT_VERSION,
24
+ elasticsearch_package,
25
+ opensearch_package,
26
+ )
22
27
  from localstack.utils.aws.arns import parse_arn
23
28
  from localstack.utils.common import (
24
29
  ShellCommandThread,
@@ -37,6 +42,9 @@ LOG = logging.getLogger(__name__)
37
42
  INTERNAL_USER_AUTH = ("localstack-internal", "localstack-internal")
38
43
  DEFAULT_BACKEND_HOST = "127.0.0.1"
39
44
 
45
+ # user that starts the opensearch process if the current user is root
46
+ OS_USER_OPENSEARCH = "localstack"
47
+
40
48
  CommandSettings = dict[str, str]
41
49
 
42
50
 
@@ -314,7 +322,7 @@ class OpensearchCluster(Server):
314
322
 
315
323
  @property
316
324
  def default_version(self) -> str:
317
- return constants.OPENSEARCH_DEFAULT_VERSION
325
+ return OPENSEARCH_DEFAULT_VERSION
318
326
 
319
327
  @property
320
328
  def version(self) -> str:
@@ -336,7 +344,7 @@ class OpensearchCluster(Server):
336
344
 
337
345
  @property
338
346
  def os_user(self):
339
- return constants.OS_USER_OPENSEARCH
347
+ return OS_USER_OPENSEARCH
340
348
 
341
349
  def health(self) -> str | None:
342
350
  return get_cluster_health_status(self.url, auth=self.auth)
@@ -580,7 +588,7 @@ class EdgeProxiedOpensearchCluster(Server):
580
588
 
581
589
  @property
582
590
  def default_version(self):
583
- return constants.OPENSEARCH_DEFAULT_VERSION
591
+ return OPENSEARCH_DEFAULT_VERSION
584
592
 
585
593
  @property
586
594
  def url(self) -> str:
@@ -658,7 +666,7 @@ class ElasticsearchCluster(OpensearchCluster):
658
666
 
659
667
  @property
660
668
  def default_version(self) -> str:
661
- return constants.ELASTICSEARCH_DEFAULT_VERSION
669
+ return ELASTICSEARCH_DEFAULT_VERSION
662
670
 
663
671
  @property
664
672
  def bin_name(self) -> str:
@@ -666,7 +674,7 @@ class ElasticsearchCluster(OpensearchCluster):
666
674
 
667
675
  @property
668
676
  def os_user(self):
669
- return constants.OS_USER_OPENSEARCH
677
+ return OS_USER_OPENSEARCH
670
678
 
671
679
  def _ensure_installed(self):
672
680
  elasticsearch_package.install(self.version)
@@ -710,7 +718,7 @@ class ElasticsearchCluster(OpensearchCluster):
710
718
  class EdgeProxiedElasticsearchCluster(EdgeProxiedOpensearchCluster):
711
719
  @property
712
720
  def default_version(self):
713
- return constants.ELASTICSEARCH_DEFAULT_VERSION
721
+ return ELASTICSEARCH_DEFAULT_VERSION
714
722
 
715
723
  def _backend_cluster(self) -> OpensearchCluster:
716
724
  return ElasticsearchCluster(
@@ -9,13 +9,6 @@ import threading
9
9
  import semver
10
10
 
11
11
  from localstack import config
12
- from localstack.constants import (
13
- ELASTICSEARCH_DEFAULT_VERSION,
14
- ELASTICSEARCH_DELETE_MODULES,
15
- ELASTICSEARCH_PLUGIN_LIST,
16
- OPENSEARCH_DEFAULT_VERSION,
17
- OPENSEARCH_PLUGIN_LIST,
18
- )
19
12
  from localstack.packages import InstallTarget, Package, PackageInstaller
20
13
  from localstack.packages.java import java_package
21
14
  from localstack.services.opensearch import versions
@@ -32,6 +25,32 @@ from localstack.utils.sync import SynchronizedDefaultDict, retry
32
25
 
33
26
  LOG = logging.getLogger(__name__)
34
27
 
28
+ # the version of opensearch which is used by default
29
+ OPENSEARCH_DEFAULT_VERSION = "OpenSearch_3.1"
30
+
31
+ # See https://docs.aws.amazon.com/opensearch-service/latest/developerguide/supported-plugins.html
32
+ OPENSEARCH_PLUGIN_LIST = [
33
+ "ingest-attachment",
34
+ "analysis-kuromoji",
35
+ ]
36
+
37
+ # the version of elasticsearch that is pre-seeded into the base image (sync with Dockerfile.base)
38
+ ELASTICSEARCH_DEFAULT_VERSION = "Elasticsearch_7.10"
39
+
40
+ # See https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/aes-supported-plugins.html
41
+ ELASTICSEARCH_PLUGIN_LIST = [
42
+ "analysis-icu",
43
+ "ingest-attachment",
44
+ "analysis-kuromoji",
45
+ "mapper-murmur3",
46
+ "mapper-size",
47
+ "analysis-phonetic",
48
+ "analysis-smartcn",
49
+ "analysis-stempel",
50
+ "analysis-ukrainian",
51
+ ]
52
+ # Default ES modules to exclude (save apprx 66MB in the final image)
53
+ ELASTICSEARCH_DELETE_MODULES = ["ingest-geoip"]
35
54
 
36
55
  _OPENSEARCH_INSTALL_LOCKS = SynchronizedDefaultDict(threading.RLock)
37
56