localstack-core 4.7.1.dev139__py3-none-any.whl → 4.10.1.dev7__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 +1 -0
- localstack/aws/api/cloudwatch/__init__.py +41 -1
- localstack/aws/api/config/__init__.py +4 -0
- localstack/aws/api/core.py +4 -0
- localstack/aws/api/ec2/__init__.py +1113 -56
- 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 +2 -0
- localstack/aws/api/s3/__init__.py +12 -0
- localstack/aws/api/s3control/__init__.py +32 -0
- localstack/aws/api/ssm/__init__.py +2 -0
- localstack/aws/client.py +7 -2
- localstack/aws/forwarder.py +52 -5
- localstack/aws/handlers/analytics.py +1 -1
- localstack/aws/handlers/logging.py +12 -2
- localstack/aws/handlers/metric_handler.py +41 -1
- localstack/aws/handlers/service.py +32 -9
- localstack/aws/protocol/parser.py +440 -21
- localstack/aws/protocol/serializer.py +684 -64
- localstack/aws/protocol/service_router.py +120 -20
- localstack/aws/skeleton.py +4 -2
- localstack/aws/spec-patches.json +58 -0
- localstack/aws/spec.py +33 -13
- localstack/cli/exceptions.py +1 -1
- localstack/cli/localstack.py +4 -4
- localstack/cli/lpm.py +3 -4
- localstack/cli/profiles.py +1 -2
- localstack/config.py +18 -12
- localstack/constants.py +4 -29
- localstack/dev/kubernetes/__main__.py +1 -1
- localstack/dev/run/paths.py +1 -1
- localstack/dns/plugins.py +5 -1
- localstack/dns/server.py +12 -3
- localstack/packages/api.py +9 -8
- localstack/packages/core.py +2 -2
- localstack/packages/plugins.py +0 -8
- localstack/runtime/init.py +1 -1
- localstack/services/apigateway/legacy/provider.py +53 -3
- 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/test_invoke.py +50 -6
- localstack/services/apigateway/next_gen/provider.py +5 -0
- localstack/services/cloudformation/engine/entities.py +12 -1
- localstack/services/cloudformation/engine/v2/change_set_model.py +0 -3
- localstack/services/cloudformation/engine/v2/change_set_model_describer.py +14 -0
- localstack/services/cloudformation/engine/v2/change_set_model_executor.py +13 -15
- localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +118 -24
- localstack/services/cloudformation/engine/v2/change_set_model_transform.py +4 -1
- localstack/services/cloudformation/engine/v2/change_set_model_validator.py +5 -14
- localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +1 -0
- localstack/services/cloudformation/engine/v2/resolving.py +6 -4
- localstack/services/cloudformation/engine/yaml_parser.py +9 -2
- localstack/services/cloudformation/resource_provider.py +5 -1
- localstack/services/cloudformation/resources.py +24149 -0
- localstack/services/cloudformation/v2/entities.py +6 -3
- localstack/services/cloudformation/v2/provider.py +172 -27
- localstack/services/cloudformation/v2/types.py +8 -4
- 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/v2/provider.py +42 -0
- localstack/services/ecr/resource_providers/aws_ecr_repository.py +5 -2
- 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/target.py +17 -9
- 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 +77 -0
- localstack/services/kms/provider.py +14 -5
- localstack/services/lambda_/invocation/internal_sqs_queue.py +5 -9
- localstack/services/lambda_/packages.py +1 -1
- localstack/services/logs/provider.py +1 -1
- 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 +6 -1
- localstack/services/opensearch/versions.py +56 -7
- localstack/services/s3/constants.py +5 -2
- localstack/services/s3/cors.py +4 -4
- localstack/services/s3/notifications.py +1 -1
- localstack/services/s3/presigned_url.py +27 -43
- localstack/services/s3/provider.py +67 -11
- localstack/services/s3/utils.py +42 -11
- localstack/services/ses/provider.py +16 -7
- localstack/services/sns/constants.py +7 -1
- localstack/services/sns/v2/models.py +167 -0
- localstack/services/sns/v2/provider.py +860 -2
- localstack/services/sns/v2/utils.py +130 -0
- localstack/services/sqs/developer_api.py +205 -0
- localstack/services/sqs/models.py +42 -3
- localstack/services/sqs/provider.py +8 -309
- localstack/services/sqs/query_api.py +1 -1
- localstack/services/sqs/utils.py +121 -2
- localstack/services/stepfunctions/asl/jsonata/jsonata.py +1 -1
- localstack/testing/aws/cloudformation_utils.py +1 -1
- localstack/testing/pytest/cloudformation/fixtures.py +3 -3
- localstack/testing/pytest/container.py +4 -5
- localstack/testing/pytest/fixtures.py +20 -19
- localstack/testing/pytest/in_memory_localstack.py +0 -4
- localstack/testing/pytest/marking.py +13 -4
- 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 +5 -0
- localstack/utils/analytics/events.py +2 -2
- localstack/utils/analytics/metadata.py +1 -2
- localstack/utils/analytics/metrics/counter.py +6 -8
- localstack/utils/analytics/publisher.py +1 -2
- localstack/utils/analytics/service_request_aggregator.py +2 -2
- localstack/utils/archives.py +11 -11
- localstack/utils/aws/arns.py +17 -9
- localstack/utils/aws/aws_responses.py +7 -7
- localstack/utils/aws/aws_stack.py +2 -3
- localstack/utils/aws/message_forwarding.py +1 -2
- localstack/utils/aws/request_context.py +4 -5
- localstack/utils/batch_policy.py +3 -3
- localstack/utils/bootstrap.py +7 -7
- localstack/utils/catalog/catalog.py +139 -0
- localstack/utils/catalog/catalog_loader.py +11 -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 +115 -131
- localstack/utils/container_utils/docker_cmd_client.py +42 -42
- localstack/utils/container_utils/docker_sdk_client.py +63 -62
- localstack/utils/diagnose.py +2 -3
- localstack/utils/docker_utils.py +3 -4
- localstack/utils/files.py +31 -7
- localstack/utils/functions.py +3 -2
- localstack/utils/http.py +4 -5
- localstack/utils/json.py +19 -5
- localstack/utils/kinesis/kinesis_connector.py +2 -1
- localstack/utils/net.py +6 -6
- localstack/utils/no_exit_argument_parser.py +2 -2
- localstack/utils/numbers.py +9 -2
- localstack/utils/objects.py +6 -5
- localstack/utils/patch.py +2 -1
- localstack/utils/run.py +10 -9
- localstack/utils/scheduler.py +11 -11
- localstack/utils/server/tcp_proxy.py +2 -2
- localstack/utils/serving.py +2 -3
- localstack/utils/strings.py +10 -11
- localstack/utils/sync.py +126 -1
- localstack/utils/tagging.py +1 -4
- localstack/utils/testutil.py +5 -4
- localstack/utils/threads.py +2 -2
- localstack/utils/time.py +11 -3
- localstack/utils/urls.py +1 -3
- localstack/version.py +2 -2
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/METADATA +17 -12
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/RECORD +168 -164
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/entry_points.txt +4 -2
- localstack_core-4.10.1.dev7.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.dev139.dist-info/plux.json +0 -1
- {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev7.data}/scripts/localstack +0 -0
- {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev7.data}/scripts/localstack-supervisor +0 -0
- {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev7.data}/scripts/localstack.bat +0 -0
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/WHEEL +0 -0
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/licenses/LICENSE.txt +0 -0
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/top_level.txt +0 -0
localstack/utils/bootstrap.py
CHANGED
|
@@ -9,9 +9,9 @@ import shlex
|
|
|
9
9
|
import signal
|
|
10
10
|
import threading
|
|
11
11
|
import time
|
|
12
|
-
from collections.abc import Iterable
|
|
12
|
+
from collections.abc import Callable, Iterable
|
|
13
13
|
from functools import wraps
|
|
14
|
-
from typing import Any
|
|
14
|
+
from typing import Any
|
|
15
15
|
|
|
16
16
|
from localstack import config, constants
|
|
17
17
|
from localstack.config import (
|
|
@@ -175,7 +175,7 @@ def get_docker_image_details(image_name: str = None) -> dict[str, str]:
|
|
|
175
175
|
return result
|
|
176
176
|
|
|
177
177
|
|
|
178
|
-
def get_image_environment_variable(env_name: str) ->
|
|
178
|
+
def get_image_environment_variable(env_name: str) -> str | None:
|
|
179
179
|
image_name = get_docker_image_to_start()
|
|
180
180
|
image_info = DOCKER_CLIENT.inspect_image(image_name)
|
|
181
181
|
image_envs = image_info["Config"]["Env"]
|
|
@@ -544,7 +544,7 @@ class ContainerConfigurators:
|
|
|
544
544
|
|
|
545
545
|
@staticmethod
|
|
546
546
|
def gateway_listen(
|
|
547
|
-
port:
|
|
547
|
+
port: int | Iterable[int] | HostAndPort | Iterable[HostAndPort],
|
|
548
548
|
):
|
|
549
549
|
"""
|
|
550
550
|
Uses the given ports to configure GATEWAY_LISTEN. For instance, ``gateway_listen([4566, 443])`` would
|
|
@@ -1000,7 +1000,7 @@ class RunningContainer:
|
|
|
1000
1000
|
return
|
|
1001
1001
|
raise
|
|
1002
1002
|
|
|
1003
|
-
def inspect(self) -> dict[str,
|
|
1003
|
+
def inspect(self) -> dict[str, dict | str]:
|
|
1004
1004
|
return self.container_client.inspect_container(container_name_or_id=self.id)
|
|
1005
1005
|
|
|
1006
1006
|
def attach(self):
|
|
@@ -1028,7 +1028,7 @@ class ContainerLogPrinter:
|
|
|
1028
1028
|
self.callback = callback
|
|
1029
1029
|
|
|
1030
1030
|
self._closed = threading.Event()
|
|
1031
|
-
self._stream:
|
|
1031
|
+
self._stream: CancellableStream | None = None
|
|
1032
1032
|
|
|
1033
1033
|
def _can_start_streaming(self):
|
|
1034
1034
|
if self._closed.is_set():
|
|
@@ -1338,7 +1338,7 @@ def start_infra_in_docker_detached(console, cli_params: dict[str, Any] = None):
|
|
|
1338
1338
|
console.log("detaching")
|
|
1339
1339
|
|
|
1340
1340
|
|
|
1341
|
-
def wait_container_is_ready(timeout:
|
|
1341
|
+
def wait_container_is_ready(timeout: float | None = None):
|
|
1342
1342
|
"""Blocks until the localstack main container is running and the ready marker has been printed."""
|
|
1343
1343
|
container_name = config.MAIN_CONTAINER_NAME
|
|
1344
1344
|
started = time.time()
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
|
|
4
|
+
from plux import Plugin
|
|
5
|
+
|
|
6
|
+
from localstack.services.cloudformation.resource_provider import (
|
|
7
|
+
plugin_manager as cfn_plugin_manager,
|
|
8
|
+
)
|
|
9
|
+
from localstack.utils.catalog.catalog_loader import RemoteCatalogLoader
|
|
10
|
+
from localstack.utils.catalog.common import (
|
|
11
|
+
AwsServiceOperationsSupportInLatest,
|
|
12
|
+
AwsServicesSupportInLatest,
|
|
13
|
+
AwsServiceSupportAtRuntime,
|
|
14
|
+
CloudFormationResourcesSupportAtRuntime,
|
|
15
|
+
CloudFormationResourcesSupportInLatest,
|
|
16
|
+
LocalstackEmulatorType,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
ServiceName = str
|
|
20
|
+
ServiceOperations = set[str]
|
|
21
|
+
ProviderName = str
|
|
22
|
+
CfnResourceName = str
|
|
23
|
+
CfnResourceMethodName = str
|
|
24
|
+
AwsServicesSupportStatus = (
|
|
25
|
+
AwsServiceSupportAtRuntime | AwsServicesSupportInLatest | AwsServiceOperationsSupportInLatest
|
|
26
|
+
)
|
|
27
|
+
CfnResourceSupportStatus = (
|
|
28
|
+
CloudFormationResourcesSupportInLatest | CloudFormationResourcesSupportAtRuntime
|
|
29
|
+
)
|
|
30
|
+
CfnResourceCatalog = dict[LocalstackEmulatorType, dict[CfnResourceName, set[CfnResourceMethodName]]]
|
|
31
|
+
|
|
32
|
+
LOG = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CatalogPlugin(Plugin):
|
|
36
|
+
namespace = "localstack.utils.catalog"
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def _get_cfn_resources_catalog(cloudformation_resources: dict) -> CfnResourceCatalog:
|
|
40
|
+
cfn_resources_catalog = {}
|
|
41
|
+
for emulator_type, resources in cloudformation_resources.items():
|
|
42
|
+
cfn_resources_catalog[emulator_type] = {}
|
|
43
|
+
for resource_name, resource in resources.items():
|
|
44
|
+
cfn_resources_catalog[emulator_type][resource_name] = set(resource.methods)
|
|
45
|
+
return cfn_resources_catalog
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def _get_services_at_runtime() -> set[ServiceName]:
|
|
49
|
+
from localstack.services.plugins import SERVICE_PLUGINS
|
|
50
|
+
|
|
51
|
+
return set(SERVICE_PLUGINS.list_available())
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def _get_cfn_resources_available_at_runtime() -> set[CfnResourceName]:
|
|
55
|
+
return set(cfn_plugin_manager.list_names())
|
|
56
|
+
|
|
57
|
+
@abstractmethod
|
|
58
|
+
def get_aws_service_status(
|
|
59
|
+
self, service_name: str, operation_name: str | None = None
|
|
60
|
+
) -> AwsServicesSupportStatus | None:
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
@abstractmethod
|
|
64
|
+
def get_cloudformation_resource_status(
|
|
65
|
+
self, resource_name: str, service_name: str, is_pro_resource: bool = False
|
|
66
|
+
) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None:
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class AwsCatalogRuntimePlugin(CatalogPlugin):
|
|
71
|
+
name = "aws-catalog-runtime-only"
|
|
72
|
+
|
|
73
|
+
def get_aws_service_status(
|
|
74
|
+
self, service_name: str, operation_name: str | None = None
|
|
75
|
+
) -> AwsServicesSupportStatus | None:
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
def get_cloudformation_resource_status(
|
|
79
|
+
self, resource_name: str, service_name: str, is_pro_resource: bool = False
|
|
80
|
+
) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None:
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class AwsCatalogRemoteStatePlugin(CatalogPlugin):
|
|
85
|
+
name = "aws-catalog-remote-state"
|
|
86
|
+
current_emulator_type: LocalstackEmulatorType = LocalstackEmulatorType.COMMUNITY
|
|
87
|
+
services_in_latest: dict[ServiceName, dict[LocalstackEmulatorType, ServiceOperations]] = {}
|
|
88
|
+
services_at_runtime: set[ServiceName] = set()
|
|
89
|
+
cfn_resources_in_latest: CfnResourceCatalog = {}
|
|
90
|
+
cfn_resources_at_runtime: set[CfnResourceName] = set()
|
|
91
|
+
|
|
92
|
+
def __init__(self, remote_catalog_loader: RemoteCatalogLoader | None = None) -> None:
|
|
93
|
+
catalog_loader = remote_catalog_loader or RemoteCatalogLoader()
|
|
94
|
+
remote_catalog = catalog_loader.get_remote_catalog()
|
|
95
|
+
for service_name, emulators in remote_catalog.services.items():
|
|
96
|
+
for emulator_type, service_provider in emulators.items():
|
|
97
|
+
self.services_in_latest.setdefault(service_name, {})[emulator_type] = set(
|
|
98
|
+
service_provider.operations
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
self.cfn_resources_in_latest = self._get_cfn_resources_catalog(
|
|
102
|
+
remote_catalog.cloudformation_resources
|
|
103
|
+
)
|
|
104
|
+
self.cfn_resources_at_runtime = self._get_cfn_resources_available_at_runtime()
|
|
105
|
+
self.services_at_runtime = self._get_services_at_runtime()
|
|
106
|
+
|
|
107
|
+
def get_aws_service_status(
|
|
108
|
+
self, service_name: str, operation_name: str | None = None
|
|
109
|
+
) -> AwsServicesSupportStatus | None:
|
|
110
|
+
if not self.services_in_latest:
|
|
111
|
+
return None
|
|
112
|
+
if service_name not in self.services_in_latest:
|
|
113
|
+
return AwsServicesSupportInLatest.NOT_SUPPORTED
|
|
114
|
+
if self.current_emulator_type not in self.services_in_latest[service_name]:
|
|
115
|
+
return AwsServicesSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE
|
|
116
|
+
if not operation_name:
|
|
117
|
+
return AwsServicesSupportInLatest.SUPPORTED
|
|
118
|
+
if operation_name in self.services_in_latest[service_name][self.current_emulator_type]:
|
|
119
|
+
return AwsServiceOperationsSupportInLatest.SUPPORTED
|
|
120
|
+
for emulator_type in self.services_in_latest[service_name]:
|
|
121
|
+
if emulator_type is self.current_emulator_type:
|
|
122
|
+
continue
|
|
123
|
+
if operation_name in self.services_in_latest[service_name][emulator_type]:
|
|
124
|
+
return AwsServiceOperationsSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE
|
|
125
|
+
return AwsServiceOperationsSupportInLatest.NOT_SUPPORTED
|
|
126
|
+
|
|
127
|
+
def get_cloudformation_resource_status(
|
|
128
|
+
self, resource_name: str, service_name: str, is_pro_resource: bool = False
|
|
129
|
+
) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None:
|
|
130
|
+
if resource_name in self.cfn_resources_at_runtime:
|
|
131
|
+
return CloudFormationResourcesSupportAtRuntime.AVAILABLE
|
|
132
|
+
if service_name in self.services_at_runtime:
|
|
133
|
+
if resource_name in self.cfn_resources_in_latest[self.current_emulator_type]:
|
|
134
|
+
return CloudFormationResourcesSupportInLatest.SUPPORTED
|
|
135
|
+
else:
|
|
136
|
+
return CloudFormationResourcesSupportInLatest.NOT_SUPPORTED
|
|
137
|
+
if service_name in self.services_in_latest:
|
|
138
|
+
return self.get_aws_service_status(service_name, operation_name=None)
|
|
139
|
+
return AwsServicesSupportInLatest.NOT_SUPPORTED
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from localstack.utils.catalog.common import AwsRemoteCatalog
|
|
4
|
+
|
|
5
|
+
LICENSE_CATALOG_PATH = ""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RemoteCatalogLoader:
|
|
9
|
+
def get_remote_catalog(self) -> AwsRemoteCatalog:
|
|
10
|
+
with open(LICENSE_CATALOG_PATH) as f:
|
|
11
|
+
return AwsRemoteCatalog(**json.load(f))
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CloudFormationResource(BaseModel):
|
|
7
|
+
methods: list[str]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AwsServiceCatalog(BaseModel):
|
|
11
|
+
provider: str
|
|
12
|
+
operations: list[str]
|
|
13
|
+
plans: list[str]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class LocalStackMetadata(BaseModel):
|
|
17
|
+
version: str
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AwsRemoteCatalog(BaseModel):
|
|
21
|
+
schema_version: str
|
|
22
|
+
localstack: LocalStackMetadata
|
|
23
|
+
services: dict[str, dict[str, AwsServiceCatalog]]
|
|
24
|
+
cloudformation_resources: dict[str, dict[str, CloudFormationResource]]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class LocalstackEmulatorType(StrEnum):
|
|
28
|
+
COMMUNITY = "community"
|
|
29
|
+
PRO = "pro"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AwsServiceSupportAtRuntime(StrEnum):
|
|
33
|
+
AVAILABLE = "AVAILABLE"
|
|
34
|
+
AVAILABLE_WITH_LICENSE_UPGRADE = "AVAILABLE_WITH_LICENSE_UPGRADE"
|
|
35
|
+
NOT_IMPLEMENTED = "NOT_IMPLEMENTED"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class AwsServicesSupportInLatest(StrEnum):
|
|
39
|
+
SUPPORTED = "SUPPORTED"
|
|
40
|
+
SUPPORTED_WITH_LICENSE_UPGRADE = "SUPPORTED_WITH_LICENSE_UPGRADE"
|
|
41
|
+
NOT_SUPPORTED = "NOT_SUPPORTED"
|
|
42
|
+
NON_DEFAULT_PROVIDER = "NON_DEFAULT_PROVIDER"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AwsServiceOperationsSupportInLatest(StrEnum):
|
|
46
|
+
SUPPORTED = "SUPPORTED"
|
|
47
|
+
SUPPORTED_WITH_LICENSE_UPGRADE = "SUPPORTED_WITH_LICENSE_UPGRADE"
|
|
48
|
+
NOT_SUPPORTED = "NOT_SUPPORTED"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class CloudFormationResourcesSupportInLatest(StrEnum):
|
|
52
|
+
SUPPORTED = "SUPPORTED"
|
|
53
|
+
NOT_SUPPORTED = "NOT_SUPPORTED"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class CloudFormationResourcesSupportAtRuntime(StrEnum):
|
|
57
|
+
AVAILABLE = "AVAILABLE"
|
|
58
|
+
NOT_IMPLEMENTED = "NOT_IMPLEMENTED"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from plux import PluginManager
|
|
4
|
+
|
|
5
|
+
from localstack.utils.catalog.catalog import CatalogPlugin
|
|
6
|
+
from localstack.utils.objects import singleton_factory
|
|
7
|
+
|
|
8
|
+
LOG = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@singleton_factory
|
|
12
|
+
def get_aws_catalog() -> CatalogPlugin:
|
|
13
|
+
plugin_manager = PluginManager(CatalogPlugin.namespace)
|
|
14
|
+
try:
|
|
15
|
+
plugin_name = "aws-catalog-remote-state-with-license"
|
|
16
|
+
if not plugin_manager.exists(plugin_name):
|
|
17
|
+
plugin_name = "aws-catalog-remote-state"
|
|
18
|
+
return plugin_manager.load(plugin_name)
|
|
19
|
+
except Exception as e:
|
|
20
|
+
LOG.debug(
|
|
21
|
+
"Failed to load catalog plugin with the latest LocalStack services support data, falling back to catalog without remote state: %s",
|
|
22
|
+
e,
|
|
23
|
+
)
|
|
24
|
+
# Try to load runtime catalog from pro version first
|
|
25
|
+
fallback_plugin_name = "aws-catalog-runtime-only-with-license"
|
|
26
|
+
if not plugin_manager.exists(fallback_plugin_name):
|
|
27
|
+
fallback_plugin_name = "aws-catalog-runtime-only"
|
|
28
|
+
return plugin_manager.load(fallback_plugin_name)
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
import time
|
|
3
3
|
from datetime import datetime, timezone
|
|
4
4
|
from itertools import islice
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import TypedDict
|
|
6
6
|
|
|
7
7
|
from werkzeug import Response as WerkzeugResponse
|
|
8
8
|
|
|
@@ -20,8 +20,8 @@ LOG = logging.getLogger(__name__)
|
|
|
20
20
|
class SqsMetricBatchData(TypedDict, total=False):
|
|
21
21
|
MetricName: str
|
|
22
22
|
QueueName: str
|
|
23
|
-
Value:
|
|
24
|
-
Unit:
|
|
23
|
+
Value: int | None
|
|
24
|
+
Unit: str | None
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
def dimension_lambda(kwargs):
|
|
@@ -30,7 +30,7 @@ def dimension_lambda(kwargs):
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def publish_lambda_metric(
|
|
33
|
-
metric, value, kwargs, account_id:
|
|
33
|
+
metric, value, kwargs, account_id: str | None = None, region_name: str | None = None
|
|
34
34
|
):
|
|
35
35
|
# publish metric only if CloudWatch service is available
|
|
36
36
|
if not is_api_enabled("cloudwatch"):
|
|
@@ -155,7 +155,7 @@ def store_cloudwatch_logs(
|
|
|
155
155
|
log_stream_name,
|
|
156
156
|
log_output,
|
|
157
157
|
start_time=None,
|
|
158
|
-
auto_create_group:
|
|
158
|
+
auto_create_group: bool | None = True,
|
|
159
159
|
):
|
|
160
160
|
if not is_api_enabled("logs"):
|
|
161
161
|
return
|
localstack/utils/collections.py
CHANGED
|
@@ -5,10 +5,9 @@ and manipulate python collection (dicts, list, sets).
|
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
7
|
import re
|
|
8
|
-
from collections.abc import Iterable, Iterator, Mapping, Sized
|
|
8
|
+
from collections.abc import Callable, Iterable, Iterator, Mapping, Sized
|
|
9
9
|
from typing import (
|
|
10
10
|
Any,
|
|
11
|
-
Callable,
|
|
12
11
|
Optional,
|
|
13
12
|
TypedDict,
|
|
14
13
|
TypeVar,
|
|
@@ -116,7 +115,7 @@ class PaginatedList(list[_ListType]):
|
|
|
116
115
|
next_token: str = None,
|
|
117
116
|
page_size: int = None,
|
|
118
117
|
filter_function: Callable[[_ListType], bool] = None,
|
|
119
|
-
) -> tuple[list[_ListType],
|
|
118
|
+
) -> tuple[list[_ListType], str | None]:
|
|
120
119
|
if filter_function is not None:
|
|
121
120
|
result_list = list(filter(filter_function, self))
|
|
122
121
|
else:
|
|
@@ -148,7 +147,7 @@ class PaginatedList(list[_ListType]):
|
|
|
148
147
|
class CustomExpiryTTLCache(cachetools.TTLCache):
|
|
149
148
|
"""TTLCache that allows to set custom expiry times for individual keys."""
|
|
150
149
|
|
|
151
|
-
def set_expiry(self, key: Any, ttl:
|
|
150
|
+
def set_expiry(self, key: Any, ttl: float | int) -> float:
|
|
152
151
|
"""Set the expiry of the given key in a TTLCache to (<current_time> + <ttl>)"""
|
|
153
152
|
with self.timer as time:
|
|
154
153
|
# note: need to access the internal dunder API here
|
|
@@ -315,7 +314,7 @@ def is_list_or_tuple(obj) -> bool:
|
|
|
315
314
|
return isinstance(obj, (list, tuple))
|
|
316
315
|
|
|
317
316
|
|
|
318
|
-
def ensure_list(obj: Any, wrap_none=False) ->
|
|
317
|
+
def ensure_list(obj: Any, wrap_none=False) -> list | None:
|
|
319
318
|
"""Wrap the given object in a list, or return the object itself if it already is a list."""
|
|
320
319
|
if obj is None and not wrap_none:
|
|
321
320
|
return obj
|
|
@@ -414,7 +413,7 @@ def items_equivalent(list1, list2, comparator):
|
|
|
414
413
|
return True
|
|
415
414
|
|
|
416
415
|
|
|
417
|
-
def is_none_or_empty(obj:
|
|
416
|
+
def is_none_or_empty(obj: str | None | list | None) -> bool:
|
|
418
417
|
return (
|
|
419
418
|
obj is None
|
|
420
419
|
or (isinstance(obj, str) and obj.strip() == "")
|
|
@@ -475,7 +474,7 @@ def convert_to_typed_dict(typed_dict: type[T], obj: dict, strict: bool = False)
|
|
|
475
474
|
return result
|
|
476
475
|
|
|
477
476
|
|
|
478
|
-
def dict_multi_values(elements:
|
|
477
|
+
def dict_multi_values(elements: list | dict) -> dict[str, list[Any]]:
|
|
479
478
|
"""
|
|
480
479
|
Return a dictionary with the original keys from the list of dictionary and the
|
|
481
480
|
values are the list of values of the original dictionary.
|
|
@@ -516,7 +515,7 @@ def split_list_by(
|
|
|
516
515
|
return truthy, falsy
|
|
517
516
|
|
|
518
517
|
|
|
519
|
-
def is_comma_delimited_list(string: str, item_regex:
|
|
518
|
+
def is_comma_delimited_list(string: str, item_regex: str | None = None) -> bool:
|
|
520
519
|
"""
|
|
521
520
|
Checks if the given string is a comma-delimited list of items.
|
|
522
521
|
The optional `item_regex` parameter specifies the regex pattern for each item in the list.
|
|
@@ -2,7 +2,6 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
4
|
from functools import lru_cache
|
|
5
|
-
from typing import Optional
|
|
6
5
|
|
|
7
6
|
from localstack import config, constants
|
|
8
7
|
from localstack.utils.container_utils.container_client import ContainerException
|
|
@@ -13,7 +12,7 @@ LOG = logging.getLogger(__name__)
|
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
@lru_cache
|
|
16
|
-
def get_main_container_network() ->
|
|
15
|
+
def get_main_container_network() -> str | None:
|
|
17
16
|
"""
|
|
18
17
|
Gets the main network of the LocalStack container (if we run in one, bridge otherwise)
|
|
19
18
|
If there are multiple networks connected to the LocalStack container, we choose the first as "main" network
|
|
@@ -50,7 +49,7 @@ def get_main_container_network() -> Optional[str]:
|
|
|
50
49
|
|
|
51
50
|
|
|
52
51
|
@lru_cache
|
|
53
|
-
def get_endpoint_for_network(network:
|
|
52
|
+
def get_endpoint_for_network(network: str | None = None) -> str:
|
|
54
53
|
"""
|
|
55
54
|
Get the LocalStack endpoint (= IP address) on the given network.
|
|
56
55
|
If a network is given, it will return the IP address/hostname of LocalStack on that network
|