localstack-core 4.10.1.dev42__py3-none-any.whl → 4.11.2.dev14__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.
- localstack/aws/api/apigateway/__init__.py +42 -0
- localstack/aws/api/cloudformation/__init__.py +161 -0
- localstack/aws/api/ec2/__init__.py +1165 -12
- localstack/aws/api/iam/__init__.py +227 -0
- localstack/aws/api/kms/__init__.py +1 -0
- localstack/aws/api/lambda_/__init__.py +418 -66
- localstack/aws/api/logs/__init__.py +312 -0
- localstack/aws/api/opensearch/__init__.py +89 -0
- localstack/aws/api/redshift/__init__.py +69 -0
- localstack/aws/api/resourcegroupstaggingapi/__init__.py +36 -0
- localstack/aws/api/route53/__init__.py +42 -0
- localstack/aws/api/route53resolver/__init__.py +1 -0
- localstack/aws/api/s3/__init__.py +62 -0
- localstack/aws/api/secretsmanager/__init__.py +28 -23
- localstack/aws/api/stepfunctions/__init__.py +52 -10
- localstack/aws/api/sts/__init__.py +52 -0
- localstack/aws/handlers/logging.py +8 -4
- localstack/aws/handlers/service.py +11 -2
- localstack/aws/protocol/serializer.py +1 -1
- localstack/deprecations.py +0 -6
- localstack/services/acm/provider.py +4 -0
- localstack/services/apigateway/legacy/provider.py +28 -15
- localstack/services/cloudformation/engine/template_preparer.py +6 -2
- localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +12 -0
- localstack/services/cloudwatch/provider.py +10 -3
- localstack/services/cloudwatch/provider_v2.py +6 -3
- localstack/services/configservice/provider.py +5 -1
- localstack/services/dynamodb/provider.py +1 -0
- localstack/services/dynamodb/v2/provider.py +1 -0
- localstack/services/dynamodbstreams/provider.py +6 -0
- localstack/services/dynamodbstreams/v2/provider.py +6 -0
- localstack/services/ec2/provider.py +6 -0
- localstack/services/es/provider.py +6 -0
- localstack/services/events/provider.py +4 -0
- localstack/services/events/v1/provider.py +9 -0
- localstack/services/firehose/provider.py +5 -0
- localstack/services/iam/provider.py +4 -0
- localstack/services/kms/models.py +10 -20
- localstack/services/kms/provider.py +4 -0
- localstack/services/lambda_/api_utils.py +37 -20
- localstack/services/lambda_/event_source_mapping/pollers/stream_poller.py +1 -1
- localstack/services/lambda_/invocation/assignment.py +4 -1
- localstack/services/lambda_/invocation/execution_environment.py +21 -2
- localstack/services/lambda_/invocation/lambda_models.py +27 -2
- localstack/services/lambda_/invocation/lambda_service.py +51 -3
- localstack/services/lambda_/invocation/models.py +9 -1
- localstack/services/lambda_/invocation/version_manager.py +18 -3
- localstack/services/lambda_/provider.py +239 -95
- localstack/services/lambda_/resource_providers/aws_lambda_function.py +33 -1
- localstack/services/lambda_/runtimes.py +3 -1
- localstack/services/logs/provider.py +9 -0
- localstack/services/opensearch/provider.py +53 -3
- localstack/services/resource_groups/provider.py +5 -1
- localstack/services/resourcegroupstaggingapi/provider.py +6 -1
- localstack/services/s3/provider.py +28 -15
- localstack/services/s3/utils.py +35 -14
- localstack/services/s3control/provider.py +101 -2
- localstack/services/s3control/validation.py +50 -0
- localstack/services/sns/constants.py +3 -1
- localstack/services/sns/publisher.py +15 -6
- localstack/services/sns/v2/models.py +6 -0
- localstack/services/sns/v2/provider.py +650 -19
- localstack/services/sns/v2/utils.py +12 -0
- localstack/services/stepfunctions/asl/component/common/path/result_path.py +1 -1
- localstack/services/stepfunctions/asl/component/state/state_execution/execute_state.py +0 -1
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py +0 -1
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/lambda_eval_utils.py +8 -8
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/{mock_eval_utils.py → local_mock_eval_utils.py} +13 -9
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service.py +6 -6
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_callback.py +1 -1
- localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py +4 -0
- localstack/services/stepfunctions/asl/component/test_state/state/base_mock.py +118 -0
- localstack/services/stepfunctions/asl/component/test_state/state/common.py +82 -0
- localstack/services/stepfunctions/asl/component/test_state/state/execution.py +139 -0
- localstack/services/stepfunctions/asl/component/test_state/state/map.py +77 -0
- localstack/services/stepfunctions/asl/component/test_state/state/task.py +44 -0
- localstack/services/stepfunctions/asl/eval/environment.py +30 -22
- localstack/services/stepfunctions/asl/eval/states.py +1 -1
- localstack/services/stepfunctions/asl/eval/test_state/environment.py +49 -9
- localstack/services/stepfunctions/asl/eval/test_state/program_state.py +22 -0
- localstack/services/stepfunctions/asl/jsonata/jsonata.py +5 -1
- localstack/services/stepfunctions/asl/parse/preprocessor.py +67 -24
- localstack/services/stepfunctions/asl/parse/test_state/asl_parser.py +5 -4
- localstack/services/stepfunctions/asl/parse/test_state/preprocessor.py +222 -31
- localstack/services/stepfunctions/asl/static_analyser/test_state/test_state_analyser.py +170 -22
- localstack/services/stepfunctions/backend/execution.py +6 -6
- localstack/services/stepfunctions/backend/execution_worker.py +5 -5
- localstack/services/stepfunctions/backend/test_state/execution.py +36 -0
- localstack/services/stepfunctions/backend/test_state/execution_worker.py +33 -1
- localstack/services/stepfunctions/backend/test_state/test_state_mock.py +127 -0
- localstack/services/stepfunctions/local_mocking/__init__.py +9 -0
- localstack/services/stepfunctions/{mocking → local_mocking}/mock_config.py +24 -17
- localstack/services/stepfunctions/provider.py +78 -27
- localstack/services/stepfunctions/test_state/mock_config.py +47 -0
- localstack/testing/pytest/fixtures.py +28 -0
- localstack/testing/snapshots/transformer_utility.py +5 -0
- localstack/utils/analytics/publisher.py +37 -155
- localstack/utils/analytics/service_request_aggregator.py +6 -4
- localstack/utils/aws/arns.py +7 -0
- localstack/utils/batching.py +258 -0
- localstack/utils/collections.py +23 -11
- localstack/version.py +2 -2
- {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/METADATA +5 -5
- {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/RECORD +113 -105
- localstack_core-4.11.2.dev14.dist-info/plux.json +1 -0
- localstack/services/stepfunctions/mocking/__init__.py +0 -0
- localstack/utils/batch_policy.py +0 -124
- localstack_core-4.10.1.dev42.dist-info/plux.json +0 -1
- /localstack/services/stepfunctions/{mocking → local_mocking}/mock_config_file.py +0 -0
- {localstack_core-4.10.1.dev42.data → localstack_core-4.11.2.dev14.data}/scripts/localstack +0 -0
- {localstack_core-4.10.1.dev42.data → localstack_core-4.11.2.dev14.data}/scripts/localstack-supervisor +0 -0
- {localstack_core-4.10.1.dev42.data → localstack_core-4.11.2.dev14.data}/scripts/localstack.bat +0 -0
- {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/WHEEL +0 -0
- {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/entry_points.txt +0 -0
- {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/licenses/LICENSE.txt +0 -0
- {localstack_core-4.10.1.dev42.dist-info → localstack_core-4.11.2.dev14.dist-info}/top_level.txt +0 -0
|
@@ -13,6 +13,7 @@ Definition = str
|
|
|
13
13
|
Enabled = bool
|
|
14
14
|
ErrorMessage = str
|
|
15
15
|
EvaluationFailureLocation = str
|
|
16
|
+
ExceptionHandlerIndex = int
|
|
16
17
|
HTTPBody = str
|
|
17
18
|
HTTPHeaders = str
|
|
18
19
|
HTTPMethod = str
|
|
@@ -22,10 +23,14 @@ HTTPStatusMessage = str
|
|
|
22
23
|
Identity = str
|
|
23
24
|
IncludeExecutionData = bool
|
|
24
25
|
IncludeExecutionDataGetExecutionHistory = bool
|
|
26
|
+
InspectionMaxConcurrency = int
|
|
27
|
+
InspectionToleratedFailureCount = int
|
|
28
|
+
InspectionToleratedFailurePercentage = float
|
|
25
29
|
KmsDataKeyReusePeriodSeconds = int
|
|
26
30
|
KmsKeyId = str
|
|
27
31
|
ListExecutionsPageToken = str
|
|
28
32
|
LongArn = str
|
|
33
|
+
MapIterationFailureCount = int
|
|
29
34
|
MapRunLabel = str
|
|
30
35
|
MaxConcurrency = int
|
|
31
36
|
Name = str
|
|
@@ -33,6 +38,8 @@ PageSize = int
|
|
|
33
38
|
PageToken = str
|
|
34
39
|
Publish = bool
|
|
35
40
|
RedriveCount = int
|
|
41
|
+
RetrierRetryCount = int
|
|
42
|
+
RetryBackoffIntervalSeconds = int
|
|
36
43
|
RevealSecrets = bool
|
|
37
44
|
ReverseOrder = bool
|
|
38
45
|
RevisionId = str
|
|
@@ -44,6 +51,7 @@ StateName = str
|
|
|
44
51
|
TagKey = str
|
|
45
52
|
TagValue = str
|
|
46
53
|
TaskToken = str
|
|
54
|
+
TestStateStateName = str
|
|
47
55
|
ToleratedFailurePercentage = float
|
|
48
56
|
TraceHeader = str
|
|
49
57
|
URL = str
|
|
@@ -184,6 +192,12 @@ class MapRunStatus(StrEnum):
|
|
|
184
192
|
ABORTED = "ABORTED"
|
|
185
193
|
|
|
186
194
|
|
|
195
|
+
class MockResponseValidationMode(StrEnum):
|
|
196
|
+
STRICT = "STRICT"
|
|
197
|
+
PRESENT = "PRESENT"
|
|
198
|
+
NONE = "NONE"
|
|
199
|
+
|
|
200
|
+
|
|
187
201
|
class StateMachineStatus(StrEnum):
|
|
188
202
|
ACTIVE = "ACTIVE"
|
|
189
203
|
DELETING = "DELETING"
|
|
@@ -1024,6 +1038,12 @@ class GetExecutionHistoryOutput(TypedDict, total=False):
|
|
|
1024
1038
|
nextToken: PageToken | None
|
|
1025
1039
|
|
|
1026
1040
|
|
|
1041
|
+
class InspectionErrorDetails(TypedDict, total=False):
|
|
1042
|
+
catchIndex: ExceptionHandlerIndex | None
|
|
1043
|
+
retryIndex: ExceptionHandlerIndex | None
|
|
1044
|
+
retryBackoffIntervalSeconds: RetryBackoffIntervalSeconds | None
|
|
1045
|
+
|
|
1046
|
+
|
|
1027
1047
|
class InspectionDataResponse(TypedDict, total=False):
|
|
1028
1048
|
protocol: HTTPProtocol | None
|
|
1029
1049
|
statusCode: HTTPStatusCode | None
|
|
@@ -1051,6 +1071,14 @@ class InspectionData(TypedDict, total=False):
|
|
|
1051
1071
|
request: InspectionDataRequest | None
|
|
1052
1072
|
response: InspectionDataResponse | None
|
|
1053
1073
|
variables: SensitiveData | None
|
|
1074
|
+
errorDetails: InspectionErrorDetails | None
|
|
1075
|
+
afterItemsPath: SensitiveData | None
|
|
1076
|
+
afterItemSelector: SensitiveData | None
|
|
1077
|
+
afterItemBatcher: SensitiveData | None
|
|
1078
|
+
afterItemsPointer: SensitiveData | None
|
|
1079
|
+
toleratedFailureCount: InspectionToleratedFailureCount | None
|
|
1080
|
+
toleratedFailurePercentage: InspectionToleratedFailurePercentage | None
|
|
1081
|
+
maxConcurrency: InspectionMaxConcurrency | None
|
|
1054
1082
|
|
|
1055
1083
|
|
|
1056
1084
|
class ListActivitiesInput(ServiceRequest):
|
|
@@ -1165,6 +1193,17 @@ class ListTagsForResourceOutput(TypedDict, total=False):
|
|
|
1165
1193
|
tags: TagList | None
|
|
1166
1194
|
|
|
1167
1195
|
|
|
1196
|
+
class MockErrorOutput(TypedDict, total=False):
|
|
1197
|
+
error: SensitiveError | None
|
|
1198
|
+
cause: SensitiveCause | None
|
|
1199
|
+
|
|
1200
|
+
|
|
1201
|
+
class MockInput(TypedDict, total=False):
|
|
1202
|
+
result: SensitiveData | None
|
|
1203
|
+
errorOutput: MockErrorOutput | None
|
|
1204
|
+
fieldValidationMode: MockResponseValidationMode | None
|
|
1205
|
+
|
|
1206
|
+
|
|
1168
1207
|
class PublishStateMachineVersionInput(ServiceRequest):
|
|
1169
1208
|
stateMachineArn: Arn
|
|
1170
1209
|
revisionId: RevisionId | None
|
|
@@ -1271,6 +1310,13 @@ class TagResourceOutput(TypedDict, total=False):
|
|
|
1271
1310
|
pass
|
|
1272
1311
|
|
|
1273
1312
|
|
|
1313
|
+
class TestStateConfiguration(TypedDict, total=False):
|
|
1314
|
+
retrierRetryCount: RetrierRetryCount | None
|
|
1315
|
+
errorCausedByState: TestStateStateName | None
|
|
1316
|
+
mapIterationFailureCount: MapIterationFailureCount | None
|
|
1317
|
+
mapItemReaderData: SensitiveData | None
|
|
1318
|
+
|
|
1319
|
+
|
|
1274
1320
|
class TestStateInput(ServiceRequest):
|
|
1275
1321
|
definition: Definition
|
|
1276
1322
|
roleArn: Arn | None
|
|
@@ -1278,6 +1324,10 @@ class TestStateInput(ServiceRequest):
|
|
|
1278
1324
|
inspectionLevel: InspectionLevel | None
|
|
1279
1325
|
revealSecrets: RevealSecrets | None
|
|
1280
1326
|
variables: SensitiveData | None
|
|
1327
|
+
stateName: TestStateStateName | None
|
|
1328
|
+
mock: MockInput | None
|
|
1329
|
+
context: SensitiveData | None
|
|
1330
|
+
stateConfiguration: TestStateConfiguration | None
|
|
1281
1331
|
|
|
1282
1332
|
|
|
1283
1333
|
class TestStateOutput(TypedDict, total=False):
|
|
@@ -1641,17 +1691,9 @@ class StepfunctionsApi:
|
|
|
1641
1691
|
) -> TagResourceOutput:
|
|
1642
1692
|
raise NotImplementedError
|
|
1643
1693
|
|
|
1644
|
-
@handler("TestState")
|
|
1694
|
+
@handler("TestState", expand=False)
|
|
1645
1695
|
def test_state(
|
|
1646
|
-
self,
|
|
1647
|
-
context: RequestContext,
|
|
1648
|
-
definition: Definition,
|
|
1649
|
-
role_arn: Arn | None = None,
|
|
1650
|
-
input: SensitiveData | None = None,
|
|
1651
|
-
inspection_level: InspectionLevel | None = None,
|
|
1652
|
-
reveal_secrets: RevealSecrets | None = None,
|
|
1653
|
-
variables: SensitiveData | None = None,
|
|
1654
|
-
**kwargs,
|
|
1696
|
+
self, context: RequestContext, request: TestStateInput, **kwargs
|
|
1655
1697
|
) -> TestStateOutput:
|
|
1656
1698
|
raise NotImplementedError
|
|
1657
1699
|
|
|
@@ -29,13 +29,17 @@ idpCommunicationErrorMessage = str
|
|
|
29
29
|
idpRejectedClaimMessage = str
|
|
30
30
|
invalidAuthorizationMessage = str
|
|
31
31
|
invalidIdentityTokenMessage = str
|
|
32
|
+
jwtAlgorithmType = str
|
|
33
|
+
jwtPayloadSizeExceededException = str
|
|
32
34
|
malformedPolicyDocumentMessage = str
|
|
33
35
|
nonNegativeIntegerType = int
|
|
36
|
+
outboundWebIdentityFederationDisabledException = str
|
|
34
37
|
packedPolicyTooLargeMessage = str
|
|
35
38
|
regionDisabledMessage = str
|
|
36
39
|
roleDurationSecondsType = int
|
|
37
40
|
roleSessionNameType = str
|
|
38
41
|
serialNumberType = str
|
|
42
|
+
sessionDurationEscalationException = str
|
|
39
43
|
sessionPolicyDocumentType = str
|
|
40
44
|
sourceIdentityType = str
|
|
41
45
|
tagKeyType = str
|
|
@@ -48,6 +52,9 @@ urlType = str
|
|
|
48
52
|
userIdType = str
|
|
49
53
|
userNameType = str
|
|
50
54
|
webIdentitySubjectType = str
|
|
55
|
+
webIdentityTokenAudienceStringType = str
|
|
56
|
+
webIdentityTokenDurationSecondsType = int
|
|
57
|
+
webIdentityTokenType = str
|
|
51
58
|
|
|
52
59
|
|
|
53
60
|
class ExpiredTokenException(ServiceException):
|
|
@@ -86,12 +93,24 @@ class InvalidIdentityTokenException(ServiceException):
|
|
|
86
93
|
status_code: int = 400
|
|
87
94
|
|
|
88
95
|
|
|
96
|
+
class JWTPayloadSizeExceededException(ServiceException):
|
|
97
|
+
code: str = "JWTPayloadSizeExceededException"
|
|
98
|
+
sender_fault: bool = True
|
|
99
|
+
status_code: int = 400
|
|
100
|
+
|
|
101
|
+
|
|
89
102
|
class MalformedPolicyDocumentException(ServiceException):
|
|
90
103
|
code: str = "MalformedPolicyDocument"
|
|
91
104
|
sender_fault: bool = True
|
|
92
105
|
status_code: int = 400
|
|
93
106
|
|
|
94
107
|
|
|
108
|
+
class OutboundWebIdentityFederationDisabledException(ServiceException):
|
|
109
|
+
code: str = "OutboundWebIdentityFederationDisabledException"
|
|
110
|
+
sender_fault: bool = True
|
|
111
|
+
status_code: int = 403
|
|
112
|
+
|
|
113
|
+
|
|
95
114
|
class PackedPolicyTooLargeException(ServiceException):
|
|
96
115
|
code: str = "PackedPolicyTooLarge"
|
|
97
116
|
sender_fault: bool = True
|
|
@@ -104,6 +123,12 @@ class RegionDisabledException(ServiceException):
|
|
|
104
123
|
status_code: int = 403
|
|
105
124
|
|
|
106
125
|
|
|
126
|
+
class SessionDurationEscalationException(ServiceException):
|
|
127
|
+
code: str = "SessionDurationEscalationException"
|
|
128
|
+
sender_fault: bool = True
|
|
129
|
+
status_code: int = 403
|
|
130
|
+
|
|
131
|
+
|
|
107
132
|
class ProvidedContext(TypedDict, total=False):
|
|
108
133
|
ProviderArn: arnType | None
|
|
109
134
|
ContextAssertion: contextAssertionType | None
|
|
@@ -282,6 +307,21 @@ class GetSessionTokenResponse(TypedDict, total=False):
|
|
|
282
307
|
Credentials: Credentials | None
|
|
283
308
|
|
|
284
309
|
|
|
310
|
+
webIdentityTokenAudienceListType = list[webIdentityTokenAudienceStringType]
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class GetWebIdentityTokenRequest(ServiceRequest):
|
|
314
|
+
Audience: webIdentityTokenAudienceListType
|
|
315
|
+
DurationSeconds: webIdentityTokenDurationSecondsType | None
|
|
316
|
+
SigningAlgorithm: jwtAlgorithmType
|
|
317
|
+
Tags: tagListType | None
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class GetWebIdentityTokenResponse(TypedDict, total=False):
|
|
321
|
+
WebIdentityToken: webIdentityTokenType | None
|
|
322
|
+
Expiration: dateType | None
|
|
323
|
+
|
|
324
|
+
|
|
285
325
|
class StsApi:
|
|
286
326
|
service: str = "sts"
|
|
287
327
|
version: str = "2011-06-15"
|
|
@@ -391,3 +431,15 @@ class StsApi:
|
|
|
391
431
|
**kwargs,
|
|
392
432
|
) -> GetSessionTokenResponse:
|
|
393
433
|
raise NotImplementedError
|
|
434
|
+
|
|
435
|
+
@handler("GetWebIdentityToken")
|
|
436
|
+
def get_web_identity_token(
|
|
437
|
+
self,
|
|
438
|
+
context: RequestContext,
|
|
439
|
+
audience: webIdentityTokenAudienceListType,
|
|
440
|
+
signing_algorithm: jwtAlgorithmType,
|
|
441
|
+
duration_seconds: webIdentityTokenDurationSecondsType | None = None,
|
|
442
|
+
tags: tagListType | None = None,
|
|
443
|
+
**kwargs,
|
|
444
|
+
) -> GetWebIdentityTokenResponse:
|
|
445
|
+
raise NotImplementedError
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Handlers for logging."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
import types
|
|
5
4
|
from functools import cached_property
|
|
6
5
|
|
|
7
6
|
from localstack.aws.api import RequestContext, ServiceException
|
|
@@ -25,10 +24,14 @@ class ExceptionLogger(ExceptionHandler):
|
|
|
25
24
|
try:
|
|
26
25
|
import moto.core.exceptions
|
|
27
26
|
|
|
28
|
-
self.
|
|
27
|
+
self._skip_exceptions(
|
|
28
|
+
ServiceException,
|
|
29
|
+
moto.core.exceptions.ServiceException,
|
|
30
|
+
moto.core.exceptions.RESTError,
|
|
31
|
+
)
|
|
29
32
|
except (ModuleNotFoundError, AttributeError):
|
|
30
33
|
# Moto may not be available in stripped-down versions of LocalStack, like LocalStack S3 image.
|
|
31
|
-
self.
|
|
34
|
+
self._skip_exceptions = (ServiceException,)
|
|
32
35
|
|
|
33
36
|
def __call__(
|
|
34
37
|
self,
|
|
@@ -37,11 +40,12 @@ class ExceptionLogger(ExceptionHandler):
|
|
|
37
40
|
context: RequestContext,
|
|
38
41
|
response: Response,
|
|
39
42
|
):
|
|
40
|
-
if isinstance(exception,
|
|
43
|
+
if isinstance(exception, self._skip_exceptions):
|
|
41
44
|
# We do not want to log an error/stacktrace if the handler is working as expected, but chooses to throw
|
|
42
45
|
# a service exception. It may also throw a Moto ServiceException, which should not be logged either
|
|
43
46
|
# because ServiceExceptionHandler understands it.
|
|
44
47
|
return
|
|
48
|
+
|
|
45
49
|
if self.logger.isEnabledFor(level=logging.DEBUG):
|
|
46
50
|
self.logger.exception("exception during call chain", exc_info=exception)
|
|
47
51
|
else:
|
|
@@ -158,14 +158,17 @@ class ServiceExceptionSerializer(ExceptionHandler):
|
|
|
158
158
|
def __init__(self):
|
|
159
159
|
self.handle_internal_failures = True
|
|
160
160
|
|
|
161
|
+
self._moto_service_exception = types.EllipsisType
|
|
162
|
+
self._moto_rest_error = types.EllipsisType
|
|
163
|
+
|
|
161
164
|
try:
|
|
162
165
|
import moto.core.exceptions
|
|
163
166
|
|
|
164
167
|
self._moto_service_exception = moto.core.exceptions.ServiceException
|
|
168
|
+
self._moto_rest_error = moto.core.exceptions.RESTError
|
|
165
169
|
except (ModuleNotFoundError, AttributeError) as exc:
|
|
166
170
|
# Moto may not be available in stripped-down versions of LocalStack, like LocalStack S3 image.
|
|
167
|
-
LOG.debug("Unable to set up Moto
|
|
168
|
-
self._moto_service_exception = types.EllipsisType
|
|
171
|
+
LOG.debug("Unable to set up Moto exception translation: %s", exc)
|
|
169
172
|
|
|
170
173
|
def __call__(
|
|
171
174
|
self,
|
|
@@ -200,6 +203,12 @@ class ServiceExceptionSerializer(ExceptionHandler):
|
|
|
200
203
|
code=exception.code,
|
|
201
204
|
message=exception.message,
|
|
202
205
|
)
|
|
206
|
+
elif isinstance(exception, self._moto_rest_error):
|
|
207
|
+
# Some Moto exceptions (like ones raised by EC2) are of type RESTError.
|
|
208
|
+
error = CommonServiceException(
|
|
209
|
+
code=exception.error_type,
|
|
210
|
+
message=exception.message,
|
|
211
|
+
)
|
|
203
212
|
|
|
204
213
|
elif not isinstance(exception, ServiceException):
|
|
205
214
|
if not self.handle_internal_failures:
|
|
@@ -2192,7 +2192,7 @@ class S3ResponseSerializer(RestXMLResponseSerializer):
|
|
|
2192
2192
|
|
|
2193
2193
|
def _prepare_additional_traits_in_xml(self, root: ETree.Element | None, request_id: str):
|
|
2194
2194
|
# some tools (Serverless) require a newline after the "<?xml ...>\n" preamble line, e.g., for LocationConstraint
|
|
2195
|
-
if root and not root.tail:
|
|
2195
|
+
if root is not None and not root.tail:
|
|
2196
2196
|
root.tail = "\n"
|
|
2197
2197
|
|
|
2198
2198
|
root.attrib["xmlns"] = self.XML_NAMESPACE
|
localstack/deprecations.py
CHANGED
|
@@ -35,12 +35,6 @@ class EnvVarDeprecation:
|
|
|
35
35
|
# Please make sure this is in-sync with https://docs.localstack.cloud/references/configuration/
|
|
36
36
|
#
|
|
37
37
|
DEPRECATIONS = [
|
|
38
|
-
# Since 0.11.3 - HTTP / HTTPS multiplexing
|
|
39
|
-
EnvVarDeprecation(
|
|
40
|
-
"USE_SSL",
|
|
41
|
-
"0.11.3",
|
|
42
|
-
"Each endpoint now supports multiplexing HTTP/HTTPS traffic over the same port. Please remove this environment variable.", # noqa
|
|
43
|
-
),
|
|
44
38
|
# Since 0.12.8 - PORT_UI was removed
|
|
45
39
|
EnvVarDeprecation(
|
|
46
40
|
"PORT_WEB_UI",
|
|
@@ -10,6 +10,7 @@ from localstack.aws.api.acm import (
|
|
|
10
10
|
RequestCertificateResponse,
|
|
11
11
|
)
|
|
12
12
|
from localstack.services import moto
|
|
13
|
+
from localstack.state import StateVisitor
|
|
13
14
|
from localstack.utils.patch import patch
|
|
14
15
|
|
|
15
16
|
# reduce the validation wait time from 60 (default) to 10 seconds
|
|
@@ -100,6 +101,9 @@ def describe(describe_orig, self):
|
|
|
100
101
|
|
|
101
102
|
|
|
102
103
|
class AcmProvider(AcmApi):
|
|
104
|
+
def accept_state_visitor(self, visitor: StateVisitor):
|
|
105
|
+
visitor.visit(acm_models.acm_backends)
|
|
106
|
+
|
|
103
107
|
@handler("RequestCertificate", expand=False)
|
|
104
108
|
def request_certificate(
|
|
105
109
|
self,
|
|
@@ -42,6 +42,7 @@ from localstack.aws.api.apigateway import (
|
|
|
42
42
|
DomainName,
|
|
43
43
|
DomainNames,
|
|
44
44
|
DomainNameStatus,
|
|
45
|
+
EndpointAccessMode,
|
|
45
46
|
EndpointConfiguration,
|
|
46
47
|
EndpointType,
|
|
47
48
|
ExportResponse,
|
|
@@ -117,7 +118,11 @@ from localstack.services.apigateway.helpers import (
|
|
|
117
118
|
from localstack.services.apigateway.legacy.helpers import multi_value_dict_for_list
|
|
118
119
|
from localstack.services.apigateway.legacy.invocations import invoke_rest_api_from_request
|
|
119
120
|
from localstack.services.apigateway.legacy.router_asf import ApigatewayRouter, to_invocation_context
|
|
120
|
-
from localstack.services.apigateway.models import
|
|
121
|
+
from localstack.services.apigateway.models import (
|
|
122
|
+
ApiGatewayStore,
|
|
123
|
+
RestApiContainer,
|
|
124
|
+
apigateway_stores,
|
|
125
|
+
)
|
|
121
126
|
from localstack.services.apigateway.next_gen.execute_api.router import (
|
|
122
127
|
ApiGatewayRouter as ApiGatewayRouterNextGen,
|
|
123
128
|
)
|
|
@@ -125,6 +130,7 @@ from localstack.services.apigateway.patches import apply_patches
|
|
|
125
130
|
from localstack.services.edge import ROUTER
|
|
126
131
|
from localstack.services.moto import call_moto, call_moto_with_request
|
|
127
132
|
from localstack.services.plugins import ServiceLifecycleHook
|
|
133
|
+
from localstack.state import StateVisitor
|
|
128
134
|
from localstack.utils.aws.arns import InvalidArnException, get_partition, parse_arn
|
|
129
135
|
from localstack.utils.collections import (
|
|
130
136
|
DelSafeDict,
|
|
@@ -191,6 +197,12 @@ class ApigatewayProvider(ApigatewayApi, ServiceLifecycleHook):
|
|
|
191
197
|
apply_patches()
|
|
192
198
|
self.router.register_routes()
|
|
193
199
|
|
|
200
|
+
def accept_state_visitor(self, visitor: StateVisitor):
|
|
201
|
+
from moto.apigateway import apigateway_backends
|
|
202
|
+
|
|
203
|
+
visitor.visit(apigateway_backends)
|
|
204
|
+
visitor.visit(apigateway_stores)
|
|
205
|
+
|
|
194
206
|
@handler("TestInvokeMethod", expand=False)
|
|
195
207
|
def test_invoke_method(
|
|
196
208
|
self, context: RequestContext, request: TestInvokeMethodRequest
|
|
@@ -511,20 +523,21 @@ class ApigatewayProvider(ApigatewayApi, ServiceLifecycleHook):
|
|
|
511
523
|
self,
|
|
512
524
|
context: RequestContext,
|
|
513
525
|
domain_name: String,
|
|
514
|
-
certificate_name: String = None,
|
|
515
|
-
certificate_body: String = None,
|
|
516
|
-
certificate_private_key: String = None,
|
|
517
|
-
certificate_chain: String = None,
|
|
518
|
-
certificate_arn: String = None,
|
|
519
|
-
regional_certificate_name: String = None,
|
|
520
|
-
regional_certificate_arn: String = None,
|
|
521
|
-
endpoint_configuration: EndpointConfiguration = None,
|
|
522
|
-
tags: MapOfStringToString = None,
|
|
523
|
-
security_policy: SecurityPolicy = None,
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
526
|
+
certificate_name: String | None = None,
|
|
527
|
+
certificate_body: String | None = None,
|
|
528
|
+
certificate_private_key: String | None = None,
|
|
529
|
+
certificate_chain: String | None = None,
|
|
530
|
+
certificate_arn: String | None = None,
|
|
531
|
+
regional_certificate_name: String | None = None,
|
|
532
|
+
regional_certificate_arn: String | None = None,
|
|
533
|
+
endpoint_configuration: EndpointConfiguration | None = None,
|
|
534
|
+
tags: MapOfStringToString | None = None,
|
|
535
|
+
security_policy: SecurityPolicy | None = None,
|
|
536
|
+
endpoint_access_mode: EndpointAccessMode | None = None,
|
|
537
|
+
mutual_tls_authentication: MutualTlsAuthenticationInput | None = None,
|
|
538
|
+
ownership_verification_certificate_arn: String | None = None,
|
|
539
|
+
policy: String | None = None,
|
|
540
|
+
routing_mode: RoutingMode | None = None,
|
|
528
541
|
**kwargs,
|
|
529
542
|
) -> DomainName:
|
|
530
543
|
if not domain_name:
|
|
@@ -6,6 +6,7 @@ from localstack.services.cloudformation.engine.transformers import (
|
|
|
6
6
|
apply_global_transformations,
|
|
7
7
|
apply_intrinsic_transformations,
|
|
8
8
|
)
|
|
9
|
+
from localstack.services.cloudformation.engine.validations import ValidationError
|
|
9
10
|
from localstack.utils.json import clone_safe
|
|
10
11
|
|
|
11
12
|
LOG = logging.getLogger(__name__)
|
|
@@ -17,9 +18,12 @@ def parse_template(template: str) -> dict:
|
|
|
17
18
|
except Exception:
|
|
18
19
|
try:
|
|
19
20
|
return clone_safe(yaml_parser.parse_yaml(template))
|
|
20
|
-
except
|
|
21
|
-
|
|
21
|
+
except ValidationError:
|
|
22
|
+
# The error is handled in the yaml parsing helper
|
|
22
23
|
raise
|
|
24
|
+
except Exception:
|
|
25
|
+
# TODO: present the user with a better error message including error location
|
|
26
|
+
raise ValidationError("Template format error: YAML not well-formed.")
|
|
23
27
|
|
|
24
28
|
|
|
25
29
|
def template_to_json(template: str) -> str:
|
|
@@ -677,6 +677,13 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
|
|
|
677
677
|
node_condition = self._get_node_condition_if_exists(
|
|
678
678
|
condition_name=condition_delta.before
|
|
679
679
|
)
|
|
680
|
+
if is_nothing(node_condition):
|
|
681
|
+
# TODO: I don't think this is a possible state since for us to be evaluating the before state,
|
|
682
|
+
# we must have successfully deployed the stack and as such this case was not reached before
|
|
683
|
+
raise ValidationError(
|
|
684
|
+
f"Template error: unresolved condition dependency {condition_delta.before} in Fn::If"
|
|
685
|
+
)
|
|
686
|
+
|
|
680
687
|
condition_value = self.visit(node_condition).before
|
|
681
688
|
if condition_value:
|
|
682
689
|
arg_delta = self.visit(node_intrinsic_function.arguments.array[1])
|
|
@@ -688,6 +695,11 @@ class ChangeSetModelPreproc(ChangeSetModelVisitor):
|
|
|
688
695
|
node_condition = self._get_node_condition_if_exists(
|
|
689
696
|
condition_name=condition_delta.after
|
|
690
697
|
)
|
|
698
|
+
if is_nothing(node_condition):
|
|
699
|
+
raise ValidationError(
|
|
700
|
+
f"Template error: unresolved condition dependency {condition_delta.after} in Fn::If"
|
|
701
|
+
)
|
|
702
|
+
|
|
691
703
|
condition_value = self.visit(node_condition).after
|
|
692
704
|
if condition_value:
|
|
693
705
|
arg_delta = self.visit(node_intrinsic_function.arguments.array[1])
|
|
@@ -35,6 +35,7 @@ from localstack.services import moto
|
|
|
35
35
|
from localstack.services.cloudwatch.alarm_scheduler import AlarmScheduler
|
|
36
36
|
from localstack.services.edge import ROUTER
|
|
37
37
|
from localstack.services.plugins import SERVICE_PLUGINS, ServiceLifecycleHook
|
|
38
|
+
from localstack.state import StateVisitor
|
|
38
39
|
from localstack.utils.aws import arns
|
|
39
40
|
from localstack.utils.aws.arns import extract_account_id_from_arn, lambda_function_name
|
|
40
41
|
from localstack.utils.aws.request_context import (
|
|
@@ -306,8 +307,13 @@ class CloudwatchProvider(CloudwatchApi, ServiceLifecycleHook):
|
|
|
306
307
|
self.tags = TaggingService()
|
|
307
308
|
self.alarm_scheduler = None
|
|
308
309
|
|
|
310
|
+
def accept_state_visitor(self, visitor: StateVisitor):
|
|
311
|
+
visitor.visit(cloudwatch_backends)
|
|
312
|
+
|
|
309
313
|
def on_after_init(self):
|
|
310
314
|
ROUTER.add(PATH_GET_RAW_METRICS, self.get_raw_metrics)
|
|
315
|
+
|
|
316
|
+
def on_before_start(self):
|
|
311
317
|
self.start_alarm_scheduler()
|
|
312
318
|
|
|
313
319
|
def on_before_state_reset(self):
|
|
@@ -337,9 +343,10 @@ class CloudwatchProvider(CloudwatchApi, ServiceLifecycleHook):
|
|
|
337
343
|
self.alarm_scheduler = AlarmScheduler()
|
|
338
344
|
|
|
339
345
|
def shutdown_alarm_scheduler(self):
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
346
|
+
if self.alarm_scheduler:
|
|
347
|
+
LOG.debug("stopping cloudwatch scheduler")
|
|
348
|
+
self.alarm_scheduler.shutdown_scheduler()
|
|
349
|
+
self.alarm_scheduler = None
|
|
343
350
|
|
|
344
351
|
def delete_alarms(self, context: RequestContext, alarm_names: AlarmNames, **kwargs) -> None:
|
|
345
352
|
moto.call_moto(context)
|
|
@@ -161,6 +161,8 @@ class CloudwatchProvider(CloudwatchApi, ServiceLifecycleHook):
|
|
|
161
161
|
|
|
162
162
|
def on_after_init(self):
|
|
163
163
|
ROUTER.add(PATH_GET_RAW_METRICS, self.get_raw_metrics)
|
|
164
|
+
|
|
165
|
+
def on_before_start(self):
|
|
164
166
|
self.start_alarm_scheduler()
|
|
165
167
|
|
|
166
168
|
def on_before_state_reset(self):
|
|
@@ -192,9 +194,10 @@ class CloudwatchProvider(CloudwatchApi, ServiceLifecycleHook):
|
|
|
192
194
|
self.alarm_scheduler = AlarmScheduler()
|
|
193
195
|
|
|
194
196
|
def shutdown_alarm_scheduler(self):
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
if self.alarm_scheduler:
|
|
198
|
+
LOG.debug("stopping cloudwatch scheduler")
|
|
199
|
+
self.alarm_scheduler.shutdown_scheduler()
|
|
200
|
+
self.alarm_scheduler = None
|
|
198
201
|
|
|
199
202
|
def delete_alarms(self, context: RequestContext, alarm_names: AlarmNames, **kwargs) -> None:
|
|
200
203
|
"""
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
from localstack.aws.api.config import ConfigApi
|
|
2
|
+
from localstack.state import StateVisitor
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
class ConfigProvider(ConfigApi):
|
|
5
|
-
|
|
6
|
+
def accept_state_visitor(self, visitor: StateVisitor):
|
|
7
|
+
from moto.config.models import config_backends
|
|
8
|
+
|
|
9
|
+
visitor.visit(config_backends)
|
|
@@ -535,6 +535,7 @@ class DynamoDBProvider(DynamodbApi, ServiceLifecycleHook):
|
|
|
535
535
|
self.server = self._new_dynamodb_server()
|
|
536
536
|
self._expired_items_worker = ExpiredItemsWorker()
|
|
537
537
|
self._router_rules = []
|
|
538
|
+
# TODO: fix _event_forwarder to have lazy instantiation of the ThreadPoolExecutor
|
|
538
539
|
self._event_forwarder = EventForwarder()
|
|
539
540
|
|
|
540
541
|
def on_before_start(self):
|
|
@@ -392,6 +392,7 @@ class DynamoDBProvider(DynamodbApi, ServiceLifecycleHook):
|
|
|
392
392
|
|
|
393
393
|
def accept_state_visitor(self, visitor: StateVisitor):
|
|
394
394
|
visitor.visit(dynamodb_stores)
|
|
395
|
+
# FIXME: DDB v2 does not depend on dynamodbstreams_stores as DynamoDB Local holds all the state
|
|
395
396
|
visitor.visit(dynamodbstreams_stores)
|
|
396
397
|
visitor.visit(AssetDirectory(self.service, os.path.join(config.dirs.data, self.service)))
|
|
397
398
|
|
|
@@ -37,6 +37,7 @@ from localstack.services.dynamodbstreams.dynamodbstreams_api import (
|
|
|
37
37
|
table_name_from_stream_arn,
|
|
38
38
|
)
|
|
39
39
|
from localstack.services.plugins import ServiceLifecycleHook
|
|
40
|
+
from localstack.state import StateVisitor
|
|
40
41
|
from localstack.utils.collections import select_from_typed_dict
|
|
41
42
|
|
|
42
43
|
LOG = logging.getLogger(__name__)
|
|
@@ -57,6 +58,11 @@ class DynamoDBStreamsProvider(DynamodbstreamsApi, ServiceLifecycleHook):
|
|
|
57
58
|
def __init__(self):
|
|
58
59
|
self.shard_to_region = {}
|
|
59
60
|
|
|
61
|
+
def accept_state_visitor(self, visitor: StateVisitor):
|
|
62
|
+
from localstack.services.dynamodbstreams.models import dynamodbstreams_stores
|
|
63
|
+
|
|
64
|
+
visitor.visit(dynamodbstreams_stores)
|
|
65
|
+
|
|
60
66
|
def describe_stream(
|
|
61
67
|
self,
|
|
62
68
|
context: RequestContext,
|
|
@@ -18,6 +18,7 @@ from localstack.services.dynamodb.utils import modify_ddblocal_arns
|
|
|
18
18
|
from localstack.services.dynamodb.v2.provider import DynamoDBProvider, modify_context_region
|
|
19
19
|
from localstack.services.dynamodbstreams.dynamodbstreams_api import get_original_region
|
|
20
20
|
from localstack.services.plugins import ServiceLifecycleHook
|
|
21
|
+
from localstack.state import StateVisitor
|
|
21
22
|
from localstack.utils.aws.arns import parse_arn
|
|
22
23
|
|
|
23
24
|
LOG = logging.getLogger(__name__)
|
|
@@ -32,6 +33,11 @@ class DynamoDBStreamsProvider(DynamodbstreamsApi, ServiceLifecycleHook):
|
|
|
32
33
|
self.server = DynamodbServer.get()
|
|
33
34
|
self.shard_to_region = {}
|
|
34
35
|
|
|
36
|
+
def accept_state_visitor(self, visitor: StateVisitor):
|
|
37
|
+
# DynamoDB Streams state is entirely dependent on DynamoDB Local state, and does not hold state itself
|
|
38
|
+
# the DynamoDB provider is responsible for the persistence of DDB Streams
|
|
39
|
+
pass
|
|
40
|
+
|
|
35
41
|
def on_after_init(self):
|
|
36
42
|
# add response processor specific to ddblocal
|
|
37
43
|
handlers.modify_service_response.append(self.service, modify_ddblocal_arns)
|
|
@@ -94,6 +94,7 @@ from localstack.services.ec2.models import get_ec2_backend
|
|
|
94
94
|
from localstack.services.ec2.patches import apply_patches
|
|
95
95
|
from localstack.services.moto import call_moto, call_moto_with_request
|
|
96
96
|
from localstack.services.plugins import ServiceLifecycleHook
|
|
97
|
+
from localstack.state import StateVisitor
|
|
97
98
|
from localstack.utils.patch import patch
|
|
98
99
|
from localstack.utils.strings import first_char_to_upper, long_uid, short_uid
|
|
99
100
|
|
|
@@ -107,6 +108,11 @@ class Ec2Provider(Ec2Api, ABC, ServiceLifecycleHook):
|
|
|
107
108
|
def on_after_init(self):
|
|
108
109
|
apply_patches()
|
|
109
110
|
|
|
111
|
+
def accept_state_visitor(self, visitor: StateVisitor):
|
|
112
|
+
from moto.ec2.models import ec2_backends
|
|
113
|
+
|
|
114
|
+
visitor.visit(ec2_backends)
|
|
115
|
+
|
|
110
116
|
@handler("DescribeAvailabilityZones", expand=False)
|
|
111
117
|
def describe_availability_zones(
|
|
112
118
|
self,
|
|
@@ -68,6 +68,7 @@ from localstack.aws.api.opensearch import (
|
|
|
68
68
|
)
|
|
69
69
|
from localstack.aws.connect import connect_to
|
|
70
70
|
from localstack.services.opensearch.packages import ELASTICSEARCH_DEFAULT_VERSION
|
|
71
|
+
from localstack.state import StateVisitor
|
|
71
72
|
|
|
72
73
|
|
|
73
74
|
def _version_to_opensearch(
|
|
@@ -208,6 +209,11 @@ def exception_mapper():
|
|
|
208
209
|
|
|
209
210
|
|
|
210
211
|
class EsProvider(EsApi):
|
|
212
|
+
def accept_state_visitor(self, visitor: StateVisitor):
|
|
213
|
+
# ES state entirely depends on `opensearch`, and delegates its entire state to it
|
|
214
|
+
# we do not need to manage state in ES
|
|
215
|
+
pass
|
|
216
|
+
|
|
211
217
|
def create_elasticsearch_domain(
|
|
212
218
|
self,
|
|
213
219
|
context: RequestContext,
|
|
@@ -168,6 +168,7 @@ from localstack.services.events.utils import (
|
|
|
168
168
|
recursive_remove_none_values_from_dict,
|
|
169
169
|
)
|
|
170
170
|
from localstack.services.plugins import ServiceLifecycleHook
|
|
171
|
+
from localstack.state import StateVisitor
|
|
171
172
|
from localstack.utils.common import truncate
|
|
172
173
|
from localstack.utils.event_matcher import matches_event
|
|
173
174
|
from localstack.utils.strings import long_uid
|
|
@@ -246,6 +247,9 @@ class EventsProvider(EventsApi, ServiceLifecycleHook):
|
|
|
246
247
|
self._connection_service_store: ConnectionServiceDict = {}
|
|
247
248
|
self._api_destination_service_store: ApiDestinationServiceDict = {}
|
|
248
249
|
|
|
250
|
+
def accept_state_visitor(self, visitor: StateVisitor):
|
|
251
|
+
visitor.visit(events_stores)
|
|
252
|
+
|
|
249
253
|
def on_before_start(self):
|
|
250
254
|
JobScheduler.start()
|
|
251
255
|
|