localstack-core 4.7.1.dev139__py3-none-any.whl → 4.10.1.dev42__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.

Potentially problematic release.


This version of localstack-core might be problematic. Click here for more details.

Files changed (208) hide show
  1. localstack/aws/api/acm/__init__.py +122 -122
  2. localstack/aws/api/apigateway/__init__.py +560 -559
  3. localstack/aws/api/cloudcontrol/__init__.py +63 -63
  4. localstack/aws/api/cloudformation/__init__.py +1041 -969
  5. localstack/aws/api/cloudwatch/__init__.py +408 -368
  6. localstack/aws/api/config/__init__.py +788 -786
  7. localstack/aws/api/core.py +4 -0
  8. localstack/aws/api/dynamodb/__init__.py +753 -759
  9. localstack/aws/api/dynamodbstreams/__init__.py +74 -74
  10. localstack/aws/api/ec2/__init__.py +9713 -8573
  11. localstack/aws/api/es/__init__.py +453 -453
  12. localstack/aws/api/events/__init__.py +552 -552
  13. localstack/aws/api/firehose/__init__.py +541 -543
  14. localstack/aws/api/iam/__init__.py +646 -572
  15. localstack/aws/api/kinesis/__init__.py +251 -144
  16. localstack/aws/api/kms/__init__.py +343 -333
  17. localstack/aws/api/lambda_/__init__.py +585 -571
  18. localstack/aws/api/logs/__init__.py +682 -666
  19. localstack/aws/api/opensearch/__init__.py +814 -785
  20. localstack/aws/api/pipes/__init__.py +336 -336
  21. localstack/aws/api/redshift/__init__.py +1192 -1164
  22. localstack/aws/api/resource_groups/__init__.py +175 -175
  23. localstack/aws/api/resourcegroupstaggingapi/__init__.py +67 -67
  24. localstack/aws/api/route53/__init__.py +256 -254
  25. localstack/aws/api/route53resolver/__init__.py +396 -396
  26. localstack/aws/api/s3/__init__.py +1358 -1345
  27. localstack/aws/api/s3control/__init__.py +616 -584
  28. localstack/aws/api/scheduler/__init__.py +118 -118
  29. localstack/aws/api/secretsmanager/__init__.py +193 -193
  30. localstack/aws/api/ses/__init__.py +227 -227
  31. localstack/aws/api/sns/__init__.py +115 -115
  32. localstack/aws/api/sqs/__init__.py +100 -100
  33. localstack/aws/api/ssm/__init__.py +1978 -1970
  34. localstack/aws/api/stepfunctions/__init__.py +323 -323
  35. localstack/aws/api/sts/__init__.py +90 -66
  36. localstack/aws/api/support/__init__.py +112 -112
  37. localstack/aws/api/swf/__init__.py +378 -386
  38. localstack/aws/api/transcribe/__init__.py +425 -425
  39. localstack/aws/client.py +7 -2
  40. localstack/aws/forwarder.py +52 -5
  41. localstack/aws/handlers/analytics.py +1 -1
  42. localstack/aws/handlers/logging.py +12 -2
  43. localstack/aws/handlers/metric_handler.py +41 -1
  44. localstack/aws/handlers/service.py +43 -10
  45. localstack/aws/protocol/parser.py +440 -21
  46. localstack/aws/protocol/serializer.py +684 -64
  47. localstack/aws/protocol/service_router.py +120 -20
  48. localstack/aws/scaffold.py +15 -17
  49. localstack/aws/skeleton.py +4 -2
  50. localstack/aws/spec-patches.json +58 -0
  51. localstack/aws/spec.py +33 -13
  52. localstack/cli/exceptions.py +1 -1
  53. localstack/cli/localstack.py +10 -5
  54. localstack/cli/lpm.py +3 -4
  55. localstack/cli/profiles.py +1 -2
  56. localstack/config.py +18 -12
  57. localstack/constants.py +4 -29
  58. localstack/dev/kubernetes/__main__.py +39 -4
  59. localstack/dev/run/paths.py +1 -1
  60. localstack/dns/plugins.py +5 -1
  61. localstack/dns/server.py +12 -3
  62. localstack/packages/api.py +9 -8
  63. localstack/packages/core.py +2 -2
  64. localstack/packages/plugins.py +0 -8
  65. localstack/runtime/init.py +1 -1
  66. localstack/services/apigateway/helpers.py +5 -9
  67. localstack/services/apigateway/legacy/provider.py +85 -12
  68. localstack/services/apigateway/next_gen/execute_api/integrations/aws.py +3 -0
  69. localstack/services/apigateway/next_gen/execute_api/integrations/http.py +3 -3
  70. localstack/services/apigateway/next_gen/execute_api/test_invoke.py +50 -6
  71. localstack/services/apigateway/next_gen/provider.py +5 -0
  72. localstack/services/apigateway/patches.py +0 -9
  73. localstack/services/cloudformation/engine/entities.py +12 -1
  74. localstack/services/cloudformation/engine/v2/change_set_model.py +0 -3
  75. localstack/services/cloudformation/engine/v2/change_set_model_describer.py +14 -0
  76. localstack/services/cloudformation/engine/v2/change_set_model_executor.py +13 -15
  77. localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +118 -24
  78. localstack/services/cloudformation/engine/v2/change_set_model_transform.py +4 -1
  79. localstack/services/cloudformation/engine/v2/change_set_model_validator.py +5 -14
  80. localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +1 -0
  81. localstack/services/cloudformation/engine/v2/resolving.py +6 -4
  82. localstack/services/cloudformation/engine/yaml_parser.py +9 -2
  83. localstack/services/cloudformation/provider.py +2 -2
  84. localstack/services/cloudformation/resource_provider.py +5 -1
  85. localstack/services/cloudformation/resources.py +24149 -0
  86. localstack/services/cloudformation/v2/entities.py +6 -3
  87. localstack/services/cloudformation/v2/provider.py +178 -33
  88. localstack/services/cloudformation/v2/types.py +8 -4
  89. localstack/services/cloudwatch/provider_v2.py +25 -28
  90. localstack/services/dynamodb/packages.py +2 -1
  91. localstack/services/dynamodb/provider.py +42 -0
  92. localstack/services/dynamodb/v2/provider.py +42 -0
  93. localstack/services/ecr/resource_providers/aws_ecr_repository.py +5 -2
  94. localstack/services/es/provider.py +2 -2
  95. localstack/services/events/event_rule_engine.py +31 -13
  96. localstack/services/events/models.py +4 -5
  97. localstack/services/events/target.py +17 -9
  98. localstack/services/iam/provider.py +11 -116
  99. localstack/services/iam/resources/policy_simulator.py +133 -0
  100. localstack/services/kinesis/models.py +15 -2
  101. localstack/services/kinesis/packages.py +1 -1
  102. localstack/services/kinesis/provider.py +77 -0
  103. localstack/services/kms/models.py +34 -4
  104. localstack/services/kms/provider.py +107 -21
  105. localstack/services/lambda_/api_utils.py +3 -1
  106. localstack/services/lambda_/invocation/internal_sqs_queue.py +5 -9
  107. localstack/services/lambda_/packages.py +1 -1
  108. localstack/services/lambda_/provider.py +1 -1
  109. localstack/services/lambda_/runtimes.py +8 -3
  110. localstack/services/logs/provider.py +36 -19
  111. localstack/services/moto.py +2 -1
  112. localstack/services/opensearch/cluster.py +15 -7
  113. localstack/services/opensearch/packages.py +26 -7
  114. localstack/services/opensearch/provider.py +6 -1
  115. localstack/services/opensearch/versions.py +56 -7
  116. localstack/services/s3/constants.py +5 -2
  117. localstack/services/s3/cors.py +4 -4
  118. localstack/services/s3/notifications.py +1 -1
  119. localstack/services/s3/presigned_url.py +27 -43
  120. localstack/services/s3/provider.py +68 -12
  121. localstack/services/s3/utils.py +42 -11
  122. localstack/services/ses/provider.py +16 -7
  123. localstack/services/sns/constants.py +7 -1
  124. localstack/services/sns/v2/models.py +190 -0
  125. localstack/services/sns/v2/provider.py +992 -2
  126. localstack/services/sns/v2/utils.py +138 -0
  127. localstack/services/sqs/developer_api.py +205 -0
  128. localstack/services/sqs/models.py +79 -13
  129. localstack/services/sqs/provider.py +8 -309
  130. localstack/services/sqs/query_api.py +1 -1
  131. localstack/services/sqs/utils.py +121 -2
  132. localstack/services/stepfunctions/asl/jsonata/jsonata.py +1 -1
  133. localstack/testing/aws/cloudformation_utils.py +1 -1
  134. localstack/testing/pytest/cloudformation/fixtures.py +3 -3
  135. localstack/testing/pytest/container.py +4 -5
  136. localstack/testing/pytest/fixtures.py +20 -19
  137. localstack/testing/pytest/in_memory_localstack.py +0 -4
  138. localstack/testing/pytest/marking.py +13 -4
  139. localstack/testing/pytest/stepfunctions/utils.py +4 -3
  140. localstack/testing/pytest/util.py +1 -1
  141. localstack/testing/pytest/validation_tracking.py +1 -2
  142. localstack/testing/snapshots/transformer_utility.py +7 -0
  143. localstack/testing/testselection/matching.py +0 -1
  144. localstack/utils/analytics/events.py +2 -2
  145. localstack/utils/analytics/metadata.py +1 -2
  146. localstack/utils/analytics/metrics/counter.py +6 -8
  147. localstack/utils/analytics/publisher.py +1 -2
  148. localstack/utils/analytics/service_request_aggregator.py +2 -2
  149. localstack/utils/archives.py +11 -11
  150. localstack/utils/aws/arns.py +17 -9
  151. localstack/utils/aws/aws_responses.py +7 -7
  152. localstack/utils/aws/aws_stack.py +2 -3
  153. localstack/utils/aws/client_types.py +0 -8
  154. localstack/utils/aws/message_forwarding.py +1 -2
  155. localstack/utils/aws/request_context.py +4 -5
  156. localstack/utils/batch_policy.py +3 -3
  157. localstack/utils/bootstrap.py +7 -7
  158. localstack/utils/catalog/catalog.py +139 -0
  159. localstack/utils/catalog/catalog_loader.py +119 -0
  160. localstack/utils/catalog/common.py +58 -0
  161. localstack/utils/catalog/plugins.py +28 -0
  162. localstack/utils/cloudwatch/cloudwatch_util.py +5 -5
  163. localstack/utils/collections.py +7 -8
  164. localstack/utils/config_listener.py +1 -1
  165. localstack/utils/container_networking.py +2 -3
  166. localstack/utils/container_utils/container_client.py +115 -131
  167. localstack/utils/container_utils/docker_cmd_client.py +42 -42
  168. localstack/utils/container_utils/docker_sdk_client.py +63 -62
  169. localstack/utils/crypto.py +109 -0
  170. localstack/utils/diagnose.py +2 -3
  171. localstack/utils/docker_utils.py +3 -4
  172. localstack/utils/files.py +31 -7
  173. localstack/utils/functions.py +3 -2
  174. localstack/utils/http.py +4 -5
  175. localstack/utils/json.py +19 -5
  176. localstack/utils/kinesis/kinesis_connector.py +2 -1
  177. localstack/utils/net.py +6 -6
  178. localstack/utils/no_exit_argument_parser.py +2 -2
  179. localstack/utils/numbers.py +9 -2
  180. localstack/utils/objects.py +6 -5
  181. localstack/utils/patch.py +2 -1
  182. localstack/utils/run.py +10 -9
  183. localstack/utils/scheduler.py +11 -11
  184. localstack/utils/server/tcp_proxy.py +2 -2
  185. localstack/utils/serving.py +2 -3
  186. localstack/utils/strings.py +10 -11
  187. localstack/utils/sync.py +126 -1
  188. localstack/utils/tagging.py +1 -4
  189. localstack/utils/testutil.py +5 -4
  190. localstack/utils/threads.py +2 -2
  191. localstack/utils/time.py +11 -3
  192. localstack/utils/urls.py +1 -3
  193. localstack/version.py +2 -2
  194. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/METADATA +19 -13
  195. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/RECORD +203 -199
  196. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/entry_points.txt +4 -2
  197. localstack_core-4.10.1.dev42.dist-info/plux.json +1 -0
  198. localstack/packages/terraform.py +0 -46
  199. localstack/services/cloudformation/deploy.html +0 -144
  200. localstack/services/cloudformation/deploy_ui.py +0 -47
  201. localstack/services/cloudformation/plugins.py +0 -12
  202. localstack_core-4.7.1.dev139.dist-info/plux.json +0 -1
  203. {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev42.data}/scripts/localstack +0 -0
  204. {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev42.data}/scripts/localstack-supervisor +0 -0
  205. {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev42.data}/scripts/localstack.bat +0 -0
  206. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/WHEEL +0 -0
  207. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/licenses/LICENSE.txt +0 -0
  208. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/top_level.txt +0 -0
@@ -3728,7 +3728,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
3728
3728
  if not layer_version:
3729
3729
  raise ValidationException(
3730
3730
  f"1 validation error detected: Value '{arn}' at 'arn' failed to satisfy constraint: Member must satisfy regular expression pattern: "
3731
- + "(arn:(aws[a-zA-Z-]*)?:lambda:[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+)"
3731
+ + "(arn:(aws[a-zA-Z-]*)?:lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+)"
3732
3732
  )
3733
3733
 
3734
3734
  store = lambda_stores[account_id][region_name]
@@ -23,7 +23,7 @@ from localstack.aws.api.lambda_ import Runtime
23
23
  # 5. Run the unit test to check the runtime setup:
24
24
  # tests.unit.services.lambda_.test_api_utils.TestApiUtils.test_check_runtime
25
25
  # 6. Review special tests including:
26
- # a) [ext] tests.aws.services.lambda_.test_lambda_endpoint_injection
26
+ # a) [pro] tests.aws.services.lambda_.test_lambda_endpoint_injection
27
27
  # 7. Before merging, run the ext integration tests to cover transparent endpoint injection testing.
28
28
  # 8. Add the new runtime to the K8 image build: https://github.com/localstack/lambda-images
29
29
  # 9. Inform the web team to update the resource browser (consider offering an endpoint in the future)
@@ -40,6 +40,7 @@ IMAGE_MAPPING: dict[Runtime, str] = {
40
40
  Runtime.nodejs16_x: "nodejs:16",
41
41
  Runtime.nodejs14_x: "nodejs:14", # deprecated Dec 4, 2023 => Jan 9, 2024 => Feb 8, 2024
42
42
  Runtime.nodejs12_x: "nodejs:12", # deprecated Mar 31, 2023 => Mar 31, 2023 => Apr 30, 2023
43
+ Runtime.python3_14: "python:3.14",
43
44
  Runtime.python3_13: "python:3.13",
44
45
  Runtime.python3_12: "python:3.12",
45
46
  Runtime.python3_11: "python:3.11",
@@ -47,6 +48,7 @@ IMAGE_MAPPING: dict[Runtime, str] = {
47
48
  Runtime.python3_9: "python:3.9",
48
49
  Runtime.python3_8: "python:3.8",
49
50
  Runtime.python3_7: "python:3.7", # deprecated Dec 4, 2023 => Jan 9, 2024 => Feb 8, 2024
51
+ Runtime.java25: "java:25",
50
52
  Runtime.java21: "java:21",
51
53
  Runtime.java17: "java:17",
52
54
  Runtime.java11: "java:11",
@@ -116,6 +118,7 @@ RUNTIMES_AGGREGATED = {
116
118
  Runtime.nodejs16_x,
117
119
  ],
118
120
  "python": [
121
+ Runtime.python3_14,
119
122
  Runtime.python3_13,
120
123
  Runtime.python3_12,
121
124
  Runtime.python3_11,
@@ -124,6 +127,7 @@ RUNTIMES_AGGREGATED = {
124
127
  Runtime.python3_8,
125
128
  ],
126
129
  "java": [
130
+ Runtime.java25,
127
131
  Runtime.java21,
128
132
  Runtime.java17,
129
133
  Runtime.java11,
@@ -155,12 +159,13 @@ SNAP_START_SUPPORTED_RUNTIMES = [
155
159
  Runtime.java11,
156
160
  Runtime.java17,
157
161
  Runtime.java21,
162
+ Runtime.java25,
158
163
  Runtime.python3_12,
159
164
  Runtime.python3_13,
160
165
  Runtime.dotnet8,
161
166
  ]
162
167
 
163
168
  # An ordered list of all Lambda runtimes considered valid by AWS. Matching snapshots in test_create_lambda_exceptions
164
- VALID_RUNTIMES: str = "[nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9]"
169
+ VALID_RUNTIMES: str = "[nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, java25, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9]"
165
170
  # An ordered list of all Lambda runtimes for layers considered valid by AWS. Matching snapshots in test_layer_exceptions
166
- VALID_LAYER_RUNTIMES: str = "[ruby2.6, dotnetcore1.0, python3.7, nodejs8.10, nasa, ruby2.7, python2.7-greengrass, dotnetcore2.0, python3.8, java21, dotnet6, dotnetcore2.1, python3.9, java11, nodejs6.10, provided, dotnetcore3.1, dotnet8, java25, java17, nodejs, nodejs4.3, java8.al2, go1.x, dotnet10, nodejs20.x, go1.9, byol, nodejs10.x, provided.al2023, nodejs22.x, python3.10, java8, nodejs12.x, python3.11, nodejs24.x, nodejs8.x, python3.12, nodejs14.x, nodejs8.9, python3.13, python3.14, nodejs16.x, provided.al2, nodejs4.3-edge, nodejs18.x, ruby3.2, python3.4, ruby3.3, ruby3.4, ruby2.5, python3.6, python2.7]"
171
+ VALID_LAYER_RUNTIMES: str = "[ruby3.5, ruby2.6, dotnetcore1.0, python3.7, nodejs8.10, nasa, ruby2.7, python2.7-greengrass, dotnetcore2.0, python3.8, java21, dotnet6, dotnetcore2.1, python3.9, java11, nodejs6.10, provided, dotnetcore3.1, dotnet8, java25, java17, nodejs, nodejs4.3, java8.al2, go1.x, dotnet10, nodejs20.x, go1.9, byol, nodejs10.x, provided.al2023, nodejs22.x, python3.10, java8, nodejs12.x, python3.11, nodejs24.x, nodejs8.x, python3.12, nodejs14.x, nodejs8.9, nodejs26.x, python3.13, python3.14, nodejs16.x, python3.15, provided.al2, nodejs4.3-edge, nodejs18.x, ruby3.2, python3.4, ruby3.3, ruby3.4, ruby2.5, python3.6, python2.7]"
@@ -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
 
@@ -26,6 +26,7 @@ from localstack.aws.api.opensearch import (
26
26
  CognitoOptions,
27
27
  CognitoOptionsStatus,
28
28
  ColdStorageOptions,
29
+ CompatibleVersionsMap,
29
30
  CreateDomainRequest,
30
31
  CreateDomainResponse,
31
32
  DeleteDomainResponse,
@@ -75,7 +76,6 @@ from localstack.aws.api.opensearch import (
75
76
  VolumeType,
76
77
  VPCDerivedInfoStatus,
77
78
  )
78
- from localstack.constants import OPENSEARCH_DEFAULT_VERSION
79
79
  from localstack.services.opensearch import versions
80
80
  from localstack.services.opensearch.cluster import SecurityOptions
81
81
  from localstack.services.opensearch.cluster_manager import (
@@ -84,6 +84,7 @@ from localstack.services.opensearch.cluster_manager import (
84
84
  create_cluster_manager,
85
85
  )
86
86
  from localstack.services.opensearch.models import OpenSearchStore, opensearch_stores
87
+ from localstack.services.opensearch.packages import OPENSEARCH_DEFAULT_VERSION
87
88
  from localstack.services.plugins import ServiceLifecycleHook
88
89
  from localstack.state import AssetDirectory, StateVisitor
89
90
  from localstack.utils.aws.arns import parse_arn
@@ -650,6 +651,10 @@ class OpensearchProvider(OpensearchApi, ServiceLifecycleHook):
650
651
  for comp in versions.compatible_versions
651
652
  if comp["SourceVersion"] == version_filter
652
653
  ]
654
+ if not compatible_versions:
655
+ compatible_versions = [
656
+ CompatibleVersionsMap(SourceVersion=version_filter, TargetVersions=[])
657
+ ]
653
658
  return GetCompatibleVersionsResponse(CompatibleVersions=compatible_versions)
654
659
 
655
660
  def describe_domain_config(
@@ -13,20 +13,24 @@ from localstack.utils.common import get_arch
13
13
 
14
14
  # Internal representation of the OpenSearch versions (without the "OpenSearch_" prefix)
15
15
  _opensearch_install_versions = {
16
+ "3.1": "3.1.0",
17
+ "2.19": "2.19.3",
18
+ "2.17": "2.17.1",
19
+ "2.15": "2.15.0",
16
20
  "2.13": "2.13.0",
17
21
  "2.11": "2.11.1",
18
22
  "2.9": "2.9.0",
19
23
  "2.7": "2.7.0",
20
24
  "2.5": "2.5.0",
21
25
  "2.3": "2.3.0",
22
- "1.3": "1.3.12",
26
+ "1.3": "1.3.20",
23
27
  "1.2": "1.2.4",
24
28
  "1.1": "1.1.0",
25
29
  "1.0": "1.0.0",
26
30
  }
27
31
  # Internal representation of the Elasticsearch versions (without the "Elasticsearch_" prefix)
28
32
  _elasticsearch_install_versions = {
29
- "7.10": "7.10.0",
33
+ "7.10": "7.10.2",
30
34
  "7.9": "7.9.3",
31
35
  "7.8": "7.8.1",
32
36
  "7.7": "7.7.1",
@@ -221,6 +225,9 @@ compatible_versions = [
221
225
  "OpenSearch_2.9",
222
226
  "OpenSearch_2.11",
223
227
  "OpenSearch_2.13",
228
+ "OpenSearch_2.15",
229
+ "OpenSearch_2.17",
230
+ "OpenSearch_2.19",
224
231
  ],
225
232
  ),
226
233
  CompatibleVersionsMap(
@@ -231,28 +238,68 @@ compatible_versions = [
231
238
  "OpenSearch_2.9",
232
239
  "OpenSearch_2.11",
233
240
  "OpenSearch_2.13",
241
+ "OpenSearch_2.15",
242
+ "OpenSearch_2.17",
243
+ "OpenSearch_2.19",
234
244
  ],
235
245
  ),
236
246
  CompatibleVersionsMap(
237
247
  SourceVersion="OpenSearch_2.5",
238
- TargetVersions=["OpenSearch_2.7", "OpenSearch_2.9", "OpenSearch_2.11", "OpenSearch_2.13"],
248
+ TargetVersions=[
249
+ "OpenSearch_2.7",
250
+ "OpenSearch_2.9",
251
+ "OpenSearch_2.11",
252
+ "OpenSearch_2.13",
253
+ "OpenSearch_2.15",
254
+ "OpenSearch_2.17",
255
+ "OpenSearch_2.19",
256
+ ],
239
257
  ),
240
258
  CompatibleVersionsMap(
241
259
  SourceVersion="OpenSearch_2.7",
242
- TargetVersions=["OpenSearch_2.9", "OpenSearch_2.11", "OpenSearch_2.13"],
260
+ TargetVersions=[
261
+ "OpenSearch_2.9",
262
+ "OpenSearch_2.11",
263
+ "OpenSearch_2.13",
264
+ "OpenSearch_2.15",
265
+ "OpenSearch_2.17",
266
+ "OpenSearch_2.19",
267
+ ],
243
268
  ),
244
269
  CompatibleVersionsMap(
245
270
  SourceVersion="OpenSearch_2.9",
246
- TargetVersions=["OpenSearch_2.11", "OpenSearch_2.13"],
271
+ TargetVersions=[
272
+ "OpenSearch_2.11",
273
+ "OpenSearch_2.13",
274
+ "OpenSearch_2.15",
275
+ "OpenSearch_2.17",
276
+ "OpenSearch_2.19",
277
+ ],
247
278
  ),
248
279
  CompatibleVersionsMap(
249
280
  SourceVersion="OpenSearch_2.11",
250
- TargetVersions=["OpenSearch_2.13"],
281
+ TargetVersions=["OpenSearch_2.13", "OpenSearch_2.15", "OpenSearch_2.17", "OpenSearch_2.19"],
282
+ ),
283
+ CompatibleVersionsMap(
284
+ SourceVersion="OpenSearch_2.13",
285
+ TargetVersions=["OpenSearch_2.15", "OpenSearch_2.17", "OpenSearch_2.19"],
286
+ ),
287
+ CompatibleVersionsMap(
288
+ SourceVersion="OpenSearch_2.15",
289
+ TargetVersions=["OpenSearch_2.17", "OpenSearch_2.19"],
290
+ ),
291
+ CompatibleVersionsMap(
292
+ SourceVersion="OpenSearch_2.17",
293
+ TargetVersions=["OpenSearch_2.19"],
294
+ ),
295
+ CompatibleVersionsMap(
296
+ SourceVersion="OpenSearch_2.19",
297
+ TargetVersions=["OpenSearch_3.1"],
251
298
  ),
252
299
  ]
253
300
 
254
301
 
255
- def get_install_type_and_version(version: str) -> (EngineType, str):
302
+ def get_install_type_and_version(version: str) -> tuple[EngineType, str]:
256
303
  engine_type = EngineType(version.split("_")[0])
257
304
 
258
305
  if version not in install_versions:
@@ -297,6 +344,8 @@ def get_download_url(install_version: str, engine_type: EngineType) -> str:
297
344
  return _opensearch_url(install_version)
298
345
  elif engine_type == EngineType.Elasticsearch:
299
346
  return _es_url(install_version)
347
+ else:
348
+ raise ValueError(f"Unknown OpenSearch engine type: {engine_type}")
300
349
 
301
350
 
302
351
  def fetch_latest_versions() -> dict[str, str]: # pragma: no cover
@@ -10,8 +10,6 @@ from localstack.aws.api.s3 import (
10
10
  )
11
11
  from localstack.aws.api.s3 import Type as GranteeType
12
12
 
13
- S3_VIRTUAL_HOST_FORWARDED_HEADER = "x-s3-vhost-forwarded-for"
14
-
15
13
  S3_UPLOAD_PART_MIN_SIZE = 5242880
16
14
  """
17
15
  This is minimum size allowed by S3 when uploading more than one part for a Multipart Upload, except for the last part
@@ -21,6 +19,11 @@ This is minimum size allowed by S3 when uploading more than one part for a Multi
21
19
  DEFAULT_PRE_SIGNED_ACCESS_KEY_ID = "test"
22
20
  DEFAULT_PRE_SIGNED_SECRET_ACCESS_KEY = "test"
23
21
 
22
+ S3_HOST_ID = "9Gjjt1m+cjU4OPvX9O9/8RuvnG41MRb/18Oux2o5H5MY7ISNTlXN+Dz9IG62/ILVxhAGI0qyPfg="
23
+ """
24
+ S3 is returning a Host Id as part of its exceptions
25
+ """
26
+
24
27
  AUTHENTICATED_USERS_ACL_GROUP = "http://acs.amazonaws.com/groups/global/AuthenticatedUsers"
25
28
  ALL_USERS_ACL_GROUP = "http://acs.amazonaws.com/groups/global/AllUsers"
26
29
  LOG_DELIVERY_ACL_GROUP = "http://acs.amazonaws.com/groups/s3/LogDelivery"
@@ -21,13 +21,13 @@ from localstack.aws.protocol.op_router import RestServiceOperationRouter
21
21
  from localstack.aws.spec import get_service_catalog
22
22
  from localstack.config import S3_VIRTUAL_HOSTNAME
23
23
  from localstack.http import Request, Response
24
+ from localstack.services.s3.constants import S3_HOST_ID
24
25
  from localstack.services.s3.utils import S3_VIRTUAL_HOSTNAME_REGEX
25
26
 
26
27
  # TODO: add more logging statements
27
28
  LOG = logging.getLogger(__name__)
28
29
 
29
30
  _s3_virtual_host_regex = re.compile(S3_VIRTUAL_HOSTNAME_REGEX)
30
- FAKE_HOST_ID = "9Gjjt1m+cjU4OPvX9O9/8RuvnG41MRb/18Oux2o5H5MY7ISNTlXN+Dz9IG62/ILVxhAGI0qyPfg="
31
31
 
32
32
  # TODO: refactor those to expose the needed methods maybe in another way that both can import
33
33
  add_default_headers = CorsResponseEnricher.add_cors_headers
@@ -135,7 +135,7 @@ class S3CorsHandler(Handler):
135
135
  if is_options_request:
136
136
  context.operation = self._get_op_from_request(request)
137
137
  raise BadRequest(
138
- "Insufficient information. Origin request header needed.", HostId=FAKE_HOST_ID
138
+ "Insufficient information. Origin request header needed.", HostId=S3_HOST_ID
139
139
  )
140
140
  else:
141
141
  # If the header is missing, Amazon S3 doesn't treat the request as a cross-origin request,
@@ -167,7 +167,7 @@ class S3CorsHandler(Handler):
167
167
  context.operation = self._get_op_from_request(request)
168
168
  raise AccessForbidden(
169
169
  message,
170
- HostId=FAKE_HOST_ID,
170
+ HostId=S3_HOST_ID,
171
171
  Method=request.headers.get("Access-Control-Request-Method", "OPTIONS"),
172
172
  ResourceType="BUCKET",
173
173
  )
@@ -182,7 +182,7 @@ class S3CorsHandler(Handler):
182
182
  context.operation = self._get_op_from_request(request)
183
183
  raise AccessForbidden(
184
184
  "CORSResponse: This CORS request is not allowed. This is usually because the evalution of Origin, request method / Access-Control-Request-Method or Access-Control-Request-Headers are not whitelisted by the resource's CORS spec.",
185
- HostId=FAKE_HOST_ID,
185
+ HostId=S3_HOST_ID,
186
186
  Method=request.headers.get("Access-Control-Request-Method"),
187
187
  ResourceType="OBJECT",
188
188
  )
@@ -105,7 +105,7 @@ class S3EventNotificationContext:
105
105
  key_storage_class: StorageClass | None
106
106
 
107
107
  @classmethod
108
- def from_request_context_native(
108
+ def from_request_context(
109
109
  cls,
110
110
  request_context: RequestContext,
111
111
  s3_bucket: S3Bucket,