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.
- localstack/aws/api/cloudformation/__init__.py +18 -4
- localstack/aws/api/cloudwatch/__init__.py +41 -1
- localstack/aws/api/config/__init__.py +4 -0
- localstack/aws/api/core.py +6 -2
- localstack/aws/api/dynamodb/__init__.py +30 -0
- localstack/aws/api/ec2/__init__.py +1522 -65
- localstack/aws/api/iam/__init__.py +7 -0
- localstack/aws/api/kinesis/__init__.py +19 -0
- localstack/aws/api/kms/__init__.py +6 -0
- localstack/aws/api/lambda_/__init__.py +13 -0
- localstack/aws/api/logs/__init__.py +15 -0
- localstack/aws/api/redshift/__init__.py +9 -3
- localstack/aws/api/route53/__init__.py +5 -0
- localstack/aws/api/s3/__init__.py +12 -0
- localstack/aws/api/s3control/__init__.py +54 -0
- localstack/aws/api/ssm/__init__.py +2 -0
- localstack/aws/api/transcribe/__init__.py +17 -0
- localstack/aws/client.py +7 -2
- localstack/aws/forwarder.py +52 -5
- localstack/aws/handlers/analytics.py +1 -1
- localstack/aws/handlers/internal_requests.py +6 -1
- localstack/aws/handlers/logging.py +12 -2
- localstack/aws/handlers/metric_handler.py +41 -1
- localstack/aws/handlers/service.py +40 -20
- localstack/aws/mocking.py +2 -2
- localstack/aws/patches.py +2 -2
- localstack/aws/protocol/parser.py +459 -32
- localstack/aws/protocol/serializer.py +689 -69
- localstack/aws/protocol/service_router.py +120 -20
- localstack/aws/protocol/validate.py +1 -1
- localstack/aws/scaffold.py +1 -1
- localstack/aws/skeleton.py +4 -2
- localstack/aws/spec-patches.json +58 -0
- localstack/aws/spec.py +37 -16
- localstack/cli/exceptions.py +1 -1
- localstack/cli/localstack.py +6 -6
- localstack/cli/lpm.py +3 -4
- localstack/cli/plugins.py +1 -1
- localstack/cli/profiles.py +1 -2
- localstack/config.py +25 -18
- localstack/constants.py +4 -29
- localstack/dev/kubernetes/__main__.py +130 -7
- localstack/dev/run/configurators.py +1 -4
- localstack/dev/run/paths.py +1 -1
- localstack/dns/plugins.py +5 -1
- localstack/dns/server.py +13 -4
- localstack/logging/format.py +3 -3
- localstack/packages/api.py +9 -8
- localstack/packages/core.py +2 -2
- localstack/packages/plugins.py +0 -8
- localstack/runtime/analytics.py +3 -0
- localstack/runtime/hooks.py +1 -1
- localstack/runtime/init.py +2 -2
- localstack/runtime/main.py +5 -5
- localstack/runtime/patches.py +2 -2
- localstack/services/apigateway/helpers.py +1 -4
- localstack/services/apigateway/legacy/helpers.py +7 -8
- localstack/services/apigateway/legacy/integration.py +4 -3
- localstack/services/apigateway/legacy/invocations.py +6 -5
- localstack/services/apigateway/legacy/provider.py +148 -68
- localstack/services/apigateway/legacy/templates.py +1 -1
- localstack/services/apigateway/next_gen/execute_api/handlers/method_request.py +7 -2
- localstack/services/apigateway/next_gen/execute_api/handlers/resource_router.py +1 -2
- localstack/services/apigateway/next_gen/execute_api/integrations/aws.py +3 -0
- localstack/services/apigateway/next_gen/execute_api/integrations/http.py +3 -3
- localstack/services/apigateway/next_gen/execute_api/template_mapping.py +2 -2
- localstack/services/apigateway/next_gen/execute_api/test_invoke.py +114 -9
- localstack/services/apigateway/next_gen/provider.py +5 -0
- localstack/services/apigateway/resource_providers/aws_apigateway_resource.py +1 -1
- localstack/services/cloudformation/api_utils.py +4 -8
- localstack/services/cloudformation/cfn_utils.py +1 -1
- localstack/services/cloudformation/engine/entities.py +14 -4
- localstack/services/cloudformation/engine/template_deployer.py +6 -4
- localstack/services/cloudformation/engine/transformers.py +6 -4
- localstack/services/cloudformation/engine/v2/change_set_model.py +201 -13
- localstack/services/cloudformation/engine/v2/change_set_model_describer.py +52 -3
- localstack/services/cloudformation/engine/v2/change_set_model_executor.py +117 -76
- localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +205 -52
- localstack/services/cloudformation/engine/v2/change_set_model_transform.py +350 -116
- localstack/services/cloudformation/engine/v2/change_set_model_validator.py +56 -14
- localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +1 -0
- localstack/services/cloudformation/engine/v2/resolving.py +7 -5
- localstack/services/cloudformation/engine/yaml_parser.py +9 -2
- localstack/services/cloudformation/provider.py +7 -5
- localstack/services/cloudformation/resource_provider.py +7 -1
- localstack/services/cloudformation/resources.py +24149 -0
- localstack/services/cloudformation/service_models.py +2 -2
- localstack/services/cloudformation/v2/entities.py +19 -9
- localstack/services/cloudformation/v2/provider.py +336 -106
- localstack/services/cloudformation/v2/types.py +13 -7
- localstack/services/cloudformation/v2/utils.py +4 -1
- localstack/services/cloudwatch/alarm_scheduler.py +4 -1
- localstack/services/cloudwatch/provider.py +18 -13
- localstack/services/cloudwatch/provider_v2.py +25 -28
- localstack/services/dynamodb/packages.py +2 -1
- localstack/services/dynamodb/provider.py +42 -0
- localstack/services/dynamodb/server.py +2 -2
- localstack/services/dynamodb/v2/provider.py +42 -0
- localstack/services/ecr/resource_providers/aws_ecr_repository.py +5 -2
- localstack/services/edge.py +1 -1
- localstack/services/es/provider.py +2 -2
- localstack/services/events/event_rule_engine.py +31 -13
- localstack/services/events/models.py +4 -5
- localstack/services/events/provider.py +17 -14
- localstack/services/events/target.py +17 -9
- localstack/services/events/v1/provider.py +5 -5
- localstack/services/firehose/provider.py +14 -4
- localstack/services/iam/provider.py +11 -116
- localstack/services/iam/resources/policy_simulator.py +133 -0
- localstack/services/kinesis/models.py +15 -2
- localstack/services/kinesis/provider.py +86 -3
- localstack/services/kms/provider.py +14 -5
- localstack/services/lambda_/api_utils.py +6 -3
- localstack/services/lambda_/invocation/docker_runtime_executor.py +1 -1
- localstack/services/lambda_/invocation/event_manager.py +1 -1
- localstack/services/lambda_/invocation/internal_sqs_queue.py +5 -9
- localstack/services/lambda_/invocation/lambda_models.py +10 -7
- localstack/services/lambda_/invocation/lambda_service.py +5 -1
- localstack/services/lambda_/packages.py +1 -1
- localstack/services/lambda_/provider.py +4 -3
- localstack/services/lambda_/provider_utils.py +1 -1
- localstack/services/logs/provider.py +36 -19
- localstack/services/moto.py +2 -1
- localstack/services/opensearch/cluster.py +15 -7
- localstack/services/opensearch/packages.py +26 -7
- localstack/services/opensearch/provider.py +8 -2
- localstack/services/opensearch/versions.py +56 -7
- localstack/services/plugins.py +11 -7
- localstack/services/providers.py +10 -2
- localstack/services/redshift/provider.py +0 -21
- localstack/services/s3/constants.py +5 -2
- localstack/services/s3/cors.py +4 -4
- localstack/services/s3/models.py +1 -1
- localstack/services/s3/notifications.py +55 -39
- localstack/services/s3/presigned_url.py +35 -54
- localstack/services/s3/provider.py +73 -15
- localstack/services/s3/utils.py +42 -22
- localstack/services/s3/validation.py +46 -32
- localstack/services/s3/website_hosting.py +4 -2
- localstack/services/ses/provider.py +18 -8
- localstack/services/sns/constants.py +7 -1
- localstack/services/sns/executor.py +9 -2
- localstack/services/sns/provider.py +8 -5
- localstack/services/sns/publisher.py +31 -16
- localstack/services/sns/v2/models.py +167 -0
- localstack/services/sns/v2/provider.py +867 -0
- localstack/services/sns/v2/utils.py +130 -0
- localstack/services/sqs/constants.py +1 -1
- localstack/services/sqs/developer_api.py +205 -0
- localstack/services/sqs/models.py +48 -5
- localstack/services/sqs/provider.py +38 -311
- localstack/services/sqs/query_api.py +6 -2
- localstack/services/sqs/utils.py +121 -2
- localstack/services/ssm/provider.py +1 -1
- localstack/services/stepfunctions/asl/component/intrinsic/member.py +1 -1
- localstack/services/stepfunctions/asl/component/state/state_choice/comparison/comparison.py +5 -11
- localstack/services/stepfunctions/asl/component/state/state_choice/state_choice.py +2 -2
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py +2 -2
- localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/state_parallel.py +1 -1
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task.py +2 -2
- localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py +1 -1
- localstack/services/stepfunctions/asl/component/state/state_pass/state_pass.py +2 -2
- localstack/services/stepfunctions/asl/component/state/state_succeed/state_succeed.py +1 -1
- localstack/services/stepfunctions/asl/component/state/state_wait/state_wait.py +1 -1
- localstack/services/stepfunctions/asl/eval/environment.py +1 -1
- localstack/services/stepfunctions/asl/jsonata/jsonata.py +1 -1
- localstack/services/stepfunctions/backend/execution.py +2 -1
- localstack/services/stores.py +1 -1
- localstack/services/transcribe/provider.py +6 -1
- localstack/state/codecs.py +61 -0
- localstack/state/core.py +11 -5
- localstack/state/pickle.py +10 -49
- localstack/testing/aws/cloudformation_utils.py +1 -1
- localstack/testing/pytest/cloudformation/fixtures.py +3 -3
- localstack/testing/pytest/cloudformation/transformers.py +0 -0
- localstack/testing/pytest/container.py +4 -5
- localstack/testing/pytest/fixtures.py +33 -31
- localstack/testing/pytest/in_memory_localstack.py +0 -4
- localstack/testing/pytest/marking.py +38 -11
- localstack/testing/pytest/stepfunctions/utils.py +4 -3
- localstack/testing/pytest/util.py +1 -1
- localstack/testing/pytest/validation_tracking.py +1 -2
- localstack/testing/snapshots/transformer_utility.py +6 -1
- localstack/utils/analytics/events.py +2 -2
- localstack/utils/analytics/metadata.py +6 -4
- localstack/utils/analytics/metrics/counter.py +8 -15
- localstack/utils/analytics/publisher.py +1 -2
- localstack/utils/analytics/service_providers.py +19 -0
- localstack/utils/analytics/service_request_aggregator.py +2 -2
- localstack/utils/archives.py +11 -11
- localstack/utils/asyncio.py +2 -2
- localstack/utils/aws/arns.py +24 -29
- localstack/utils/aws/aws_responses.py +8 -8
- localstack/utils/aws/aws_stack.py +2 -3
- localstack/utils/aws/dead_letter_queue.py +1 -5
- localstack/utils/aws/message_forwarding.py +1 -2
- localstack/utils/aws/request_context.py +4 -5
- localstack/utils/aws/resources.py +1 -1
- localstack/utils/aws/templating.py +1 -1
- localstack/utils/batch_policy.py +3 -3
- localstack/utils/bootstrap.py +21 -13
- localstack/utils/catalog/catalog.py +139 -0
- localstack/utils/catalog/catalog_loader.py +119 -0
- localstack/utils/catalog/common.py +58 -0
- localstack/utils/catalog/plugins.py +28 -0
- localstack/utils/cloudwatch/cloudwatch_util.py +5 -5
- localstack/utils/collections.py +7 -8
- localstack/utils/config_listener.py +1 -1
- localstack/utils/container_networking.py +2 -3
- localstack/utils/container_utils/container_client.py +135 -136
- localstack/utils/container_utils/docker_cmd_client.py +85 -69
- localstack/utils/container_utils/docker_sdk_client.py +69 -66
- localstack/utils/crypto.py +10 -10
- localstack/utils/diagnose.py +3 -4
- localstack/utils/docker_utils.py +9 -5
- localstack/utils/files.py +33 -13
- localstack/utils/functions.py +4 -3
- localstack/utils/http.py +11 -11
- localstack/utils/json.py +20 -6
- localstack/utils/kinesis/kinesis_connector.py +2 -1
- localstack/utils/net.py +15 -9
- localstack/utils/no_exit_argument_parser.py +2 -2
- localstack/utils/numbers.py +9 -2
- localstack/utils/objects.py +7 -6
- localstack/utils/patch.py +10 -3
- localstack/utils/run.py +12 -11
- localstack/utils/scheduler.py +11 -11
- localstack/utils/server/tcp_proxy.py +2 -2
- localstack/utils/serving.py +3 -4
- localstack/utils/strings.py +15 -16
- localstack/utils/sync.py +126 -1
- localstack/utils/tagging.py +8 -6
- localstack/utils/testutil.py +8 -8
- localstack/utils/threads.py +2 -2
- localstack/utils/time.py +12 -4
- localstack/utils/urls.py +1 -3
- localstack/utils/xray/traceid.py +1 -1
- localstack/version.py +16 -3
- {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/METADATA +18 -14
- {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/RECORD +248 -239
- {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/entry_points.txt +8 -4
- localstack_core-4.10.1.dev12.dist-info/plux.json +1 -0
- localstack/packages/terraform.py +0 -46
- localstack/services/cloudformation/deploy.html +0 -144
- localstack/services/cloudformation/deploy_ui.py +0 -47
- localstack/services/cloudformation/plugins.py +0 -12
- localstack_core-4.7.1.dev49.dist-info/plux.json +0 -1
- {localstack_core-4.7.1.dev49.data → localstack_core-4.10.1.dev12.data}/scripts/localstack +0 -0
- {localstack_core-4.7.1.dev49.data → localstack_core-4.10.1.dev12.data}/scripts/localstack-supervisor +0 -0
- {localstack_core-4.7.1.dev49.data → localstack_core-4.10.1.dev12.data}/scripts/localstack.bat +0 -0
- {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/WHEEL +0 -0
- {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/licenses/LICENSE.txt +0 -0
- {localstack_core-4.7.1.dev49.dist-info → localstack_core-4.10.1.dev12.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from typing import Any
|
|
3
3
|
|
|
4
|
+
from botocore.exceptions import ParamValidationError
|
|
5
|
+
|
|
4
6
|
from localstack.services.cloudformation.engine.v2.change_set_model import (
|
|
5
|
-
Maybe,
|
|
6
7
|
NodeIntrinsicFunction,
|
|
8
|
+
NodeProperty,
|
|
9
|
+
NodeResource,
|
|
7
10
|
NodeTemplate,
|
|
8
11
|
Nothing,
|
|
9
12
|
is_nothing,
|
|
@@ -23,23 +26,15 @@ class ChangeSetModelValidator(ChangeSetModelPreproc):
|
|
|
23
26
|
def visit_node_template(self, node_template: NodeTemplate):
|
|
24
27
|
self.visit(node_template.mappings)
|
|
25
28
|
self.visit(node_template.resources)
|
|
29
|
+
self.visit(node_template.parameters)
|
|
26
30
|
|
|
27
31
|
def visit_node_intrinsic_function_fn_get_att(
|
|
28
32
|
self, node_intrinsic_function: NodeIntrinsicFunction
|
|
29
33
|
) -> PreprocEntityDelta:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
before = self._before_cache.get(node_intrinsic_function.scope, Nothing)
|
|
35
|
-
if is_nothing(before) and not is_nothing(before_arguments):
|
|
36
|
-
before = ".".join(before_arguments)
|
|
37
|
-
|
|
38
|
-
after = self._after_cache.get(node_intrinsic_function.scope, Nothing)
|
|
39
|
-
if is_nothing(after) and not is_nothing(after_arguments):
|
|
40
|
-
after = ".".join(after_arguments)
|
|
41
|
-
|
|
42
|
-
return PreprocEntityDelta(before=before, after=after)
|
|
34
|
+
try:
|
|
35
|
+
return super().visit_node_intrinsic_function_fn_get_att(node_intrinsic_function)
|
|
36
|
+
except RuntimeError:
|
|
37
|
+
return self.visit(node_intrinsic_function.arguments)
|
|
43
38
|
|
|
44
39
|
def visit_node_intrinsic_function_fn_sub(
|
|
45
40
|
self, node_intrinsic_function: NodeIntrinsicFunction
|
|
@@ -139,3 +134,50 @@ class ChangeSetModelValidator(ChangeSetModelPreproc):
|
|
|
139
134
|
if is_nothing(after) and not is_nothing(arguments_after):
|
|
140
135
|
after = _compute_sub(args=arguments_after, select_before=False)
|
|
141
136
|
return PreprocEntityDelta(before=before, after=after)
|
|
137
|
+
|
|
138
|
+
def visit_node_intrinsic_function_fn_transform(
|
|
139
|
+
self, node_intrinsic_function: NodeIntrinsicFunction
|
|
140
|
+
):
|
|
141
|
+
# TODO Research this issue:
|
|
142
|
+
# Function is already resolved in the template reaching this point
|
|
143
|
+
# But transformation is still present in update model
|
|
144
|
+
return self.visit(node_intrinsic_function.arguments)
|
|
145
|
+
|
|
146
|
+
def visit_node_intrinsic_function_fn_split(
|
|
147
|
+
self, node_intrinsic_function: NodeIntrinsicFunction
|
|
148
|
+
) -> PreprocEntityDelta:
|
|
149
|
+
try:
|
|
150
|
+
# If an argument is a Parameter it should be resolved, any other case, ignore it
|
|
151
|
+
return super().visit_node_intrinsic_function_fn_split(node_intrinsic_function)
|
|
152
|
+
except RuntimeError:
|
|
153
|
+
return self.visit(node_intrinsic_function.arguments)
|
|
154
|
+
|
|
155
|
+
def visit_node_intrinsic_function_fn_select(
|
|
156
|
+
self, node_intrinsic_function: NodeIntrinsicFunction
|
|
157
|
+
) -> PreprocEntityDelta:
|
|
158
|
+
try:
|
|
159
|
+
# If an argument is a Parameter it should be resolved, any other case, ignore it
|
|
160
|
+
return super().visit_node_intrinsic_function_fn_select(node_intrinsic_function)
|
|
161
|
+
except RuntimeError:
|
|
162
|
+
return self.visit(node_intrinsic_function.arguments)
|
|
163
|
+
|
|
164
|
+
def visit_node_resource(self, node_resource: NodeResource) -> PreprocEntityDelta:
|
|
165
|
+
try:
|
|
166
|
+
if delta := super().visit_node_resource(node_resource):
|
|
167
|
+
return delta
|
|
168
|
+
return super().visit_node_properties(node_resource.properties)
|
|
169
|
+
except RuntimeError:
|
|
170
|
+
return super().visit_node_properties(node_resource.properties)
|
|
171
|
+
|
|
172
|
+
def visit_node_property(self, node_property: NodeProperty) -> PreprocEntityDelta:
|
|
173
|
+
try:
|
|
174
|
+
return super().visit_node_property(node_property)
|
|
175
|
+
except ParamValidationError:
|
|
176
|
+
return self.visit(node_property.value)
|
|
177
|
+
|
|
178
|
+
# ignore errors from dynamic replacements
|
|
179
|
+
def _maybe_perform_dynamic_replacements(self, delta: PreprocEntityDelta) -> PreprocEntityDelta:
|
|
180
|
+
try:
|
|
181
|
+
return super()._maybe_perform_dynamic_replacements(delta)
|
|
182
|
+
except Exception:
|
|
183
|
+
return delta
|
|
@@ -54,6 +54,7 @@ class ChangeSetModelVisitor(abc.ABC):
|
|
|
54
54
|
# entities (parameters, mappings, conditions, etc.). Then compute the output fields; computing
|
|
55
55
|
# only the output fields would only result in the deployment logic of the referenced outputs
|
|
56
56
|
# being evaluated, hence enforce the visiting of all the resources first.
|
|
57
|
+
self.visit(node_template.conditions)
|
|
57
58
|
self.visit(node_template.resources)
|
|
58
59
|
self.visit(node_template.outputs)
|
|
59
60
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import logging
|
|
2
3
|
import re
|
|
3
4
|
from dataclasses import dataclass
|
|
@@ -6,11 +7,12 @@ from typing import Any
|
|
|
6
7
|
from botocore.exceptions import ClientError
|
|
7
8
|
|
|
8
9
|
from localstack.aws.connect import connect_to
|
|
9
|
-
from localstack.utils import json
|
|
10
10
|
|
|
11
11
|
LOG = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
# CloudFormation allows using dynamic references in `Fn::Sub` expressions, so we must make sure
|
|
14
|
+
# we don't capture the parameter usage by excluding ${} characters
|
|
15
|
+
REGEX_DYNAMIC_REF = re.compile(r"{{resolve:([^:]+):([^${}]+)}}")
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
@dataclass
|
|
@@ -21,7 +23,7 @@ class DynamicReference:
|
|
|
21
23
|
|
|
22
24
|
def extract_dynamic_reference(value: Any) -> DynamicReference | None:
|
|
23
25
|
if isinstance(value, str):
|
|
24
|
-
if dynamic_ref_match := REGEX_DYNAMIC_REF.
|
|
26
|
+
if dynamic_ref_match := REGEX_DYNAMIC_REF.search(value):
|
|
25
27
|
return DynamicReference(dynamic_ref_match[1], dynamic_ref_match[2])
|
|
26
28
|
return None
|
|
27
29
|
|
|
@@ -90,9 +92,9 @@ def perform_dynamic_reference_lookup(
|
|
|
90
92
|
raise RuntimeError(
|
|
91
93
|
f"JSON value for {reference.service_name}.{reference.reference_key} not present"
|
|
92
94
|
)
|
|
93
|
-
return json_secret[json_key]
|
|
95
|
+
return str(json_secret[json_key])
|
|
94
96
|
else:
|
|
95
|
-
return secret_value
|
|
97
|
+
return str(secret_value)
|
|
96
98
|
|
|
97
99
|
LOG.warning(
|
|
98
100
|
"Unsupported service for dynamic parameter: service_name=%s", reference.service_name
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import yaml
|
|
2
2
|
|
|
3
|
+
from localstack.services.cloudformation.engine.validations import ValidationError
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
def construct_raw(_, node):
|
|
5
7
|
return node.value
|
|
@@ -60,5 +62,10 @@ customloader = NoDatesSafeLoader
|
|
|
60
62
|
yaml.add_multi_constructor("!", shorthand_constructor, customloader)
|
|
61
63
|
|
|
62
64
|
|
|
63
|
-
def parse_yaml(input_data: str):
|
|
64
|
-
|
|
65
|
+
def parse_yaml(input_data: str) -> dict:
|
|
66
|
+
parsed = yaml.load(input_data, Loader=customloader)
|
|
67
|
+
|
|
68
|
+
if not isinstance(parsed, dict):
|
|
69
|
+
raise ValidationError("Template format error: unsupported structure.")
|
|
70
|
+
|
|
71
|
+
return parsed
|
|
@@ -159,7 +159,7 @@ def find_stack_instance(stack_set: StackSet, account: str, region: str):
|
|
|
159
159
|
|
|
160
160
|
def stack_not_found_error(stack_name: str):
|
|
161
161
|
# FIXME
|
|
162
|
-
raise ValidationError("Stack with id
|
|
162
|
+
raise ValidationError(f"Stack with id {stack_name} does not exist")
|
|
163
163
|
|
|
164
164
|
|
|
165
165
|
def not_found_error(message: str):
|
|
@@ -305,8 +305,8 @@ class CloudformationProvider(CloudformationApi):
|
|
|
305
305
|
deployer.deploy_stack()
|
|
306
306
|
except Exception as e:
|
|
307
307
|
stack.set_stack_status("CREATE_FAILED")
|
|
308
|
-
msg = 'Unable to create stack "
|
|
309
|
-
LOG.
|
|
308
|
+
msg = f'Unable to create stack "{stack.stack_name}": {e}'
|
|
309
|
+
LOG.error("%s", exc_info=LOG.isEnabledFor(logging.DEBUG))
|
|
310
310
|
raise ValidationError(msg) from e
|
|
311
311
|
|
|
312
312
|
return CreateStackOutput(StackId=stack.stack_id)
|
|
@@ -423,7 +423,7 @@ class CloudformationProvider(CloudformationApi):
|
|
|
423
423
|
except Exception as e:
|
|
424
424
|
stack.set_stack_status("UPDATE_FAILED")
|
|
425
425
|
msg = f'Unable to update stack "{stack_name}": {e}'
|
|
426
|
-
LOG.
|
|
426
|
+
LOG.error("%s", msg, exc_info=LOG.isEnabledFor(logging.DEBUG))
|
|
427
427
|
raise ValidationError(msg) from e
|
|
428
428
|
|
|
429
429
|
return UpdateStackOutput(StackId=stack.stack_id)
|
|
@@ -605,6 +605,8 @@ class CloudformationProvider(CloudformationApi):
|
|
|
605
605
|
req_params = request
|
|
606
606
|
change_set_type = req_params.get("ChangeSetType", "UPDATE")
|
|
607
607
|
stack_name = req_params.get("StackName")
|
|
608
|
+
if not stack_name:
|
|
609
|
+
raise ValidationError("Member must have length greater than or equal to 1")
|
|
608
610
|
change_set_name = req_params.get("ChangeSetName")
|
|
609
611
|
template_body = req_params.get("TemplateBody")
|
|
610
612
|
# s3 or secretsmanager url
|
|
@@ -1052,7 +1054,7 @@ class CloudformationProvider(CloudformationApi):
|
|
|
1052
1054
|
Description=valid_template.get("Description"), Parameters=parameters
|
|
1053
1055
|
)
|
|
1054
1056
|
except Exception as e:
|
|
1055
|
-
LOG.
|
|
1057
|
+
LOG.error("Error validating template", exc_info=LOG.isEnabledFor(logging.DEBUG))
|
|
1056
1058
|
raise ValidationError("Template Validation Error") from e
|
|
1057
1059
|
|
|
1058
1060
|
# =======================================
|
|
@@ -518,10 +518,14 @@ class ResourceProviderExecutor:
|
|
|
518
518
|
try:
|
|
519
519
|
return resource_provider.update(request)
|
|
520
520
|
except NotImplementedError:
|
|
521
|
+
feature_request_url = "https://github.com/localstack/localstack/issues/new?template=feature-request.yml"
|
|
521
522
|
LOG.warning(
|
|
522
|
-
'Unable to update resource type "%s", id "%s"'
|
|
523
|
+
'Unable to update resource type "%s", id "%s", '
|
|
524
|
+
"the update operation is not implemented for this resource. "
|
|
525
|
+
"Please consider submitting a feature request at this URL: %s",
|
|
523
526
|
request.resource_type,
|
|
524
527
|
request.logical_resource_id,
|
|
528
|
+
feature_request_url,
|
|
525
529
|
)
|
|
526
530
|
if request.previous_state is None:
|
|
527
531
|
# this is an issue with our update detection. We should never be in this state.
|
|
@@ -563,6 +567,8 @@ class ResourceProviderExecutor:
|
|
|
563
567
|
@staticmethod
|
|
564
568
|
def try_load_resource_provider(resource_type: str) -> ResourceProvider | None:
|
|
565
569
|
# TODO: unify namespace of plugins
|
|
570
|
+
if resource_type and resource_type.startswith("Custom"):
|
|
571
|
+
resource_type = "AWS::CloudFormation::CustomResource"
|
|
566
572
|
|
|
567
573
|
# 1. try to load pro resource provider
|
|
568
574
|
# prioritise pro resource providers
|