Skip to content

Commit b1bbde2

Browse files
committed
fix CFN Catalog building and add typing + test
1 parent 79ef3c3 commit b1bbde2

File tree

2 files changed

+47
-30
lines changed

2 files changed

+47
-30
lines changed

localstack-core/localstack/utils/catalog/catalog.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
CfnResourceSupportStatus = (
2828
CloudFormationResourcesSupportInLatest | CloudFormationResourcesSupportAtRuntime
2929
)
30+
CfnResourceCatalog = dict[LocalstackEmulatorType, dict[CfnResourceName, set[CfnResourceMethodName]]]
3031

3132
LOG = logging.getLogger(__name__)
3233

@@ -35,21 +36,22 @@ class CatalogPlugin(Plugin):
3536
namespace = "localstack.utils.catalog"
3637

3738
@staticmethod
38-
def _get_cfn_resources_catalog(cloudformation_resources: dict):
39+
def _get_cfn_resources_catalog(cloudformation_resources: dict) -> CfnResourceCatalog:
3940
cfn_resources_catalog = {}
4041
for emulator_type, resources in cloudformation_resources.items():
42+
cfn_resources_catalog[emulator_type] = {}
4143
for resource_name, resource in resources.items():
42-
cfn_resources_catalog[emulator_type] = {resource_name: set(resource.methods)}
44+
cfn_resources_catalog[emulator_type][resource_name] = set(resource.methods)
4345
return cfn_resources_catalog
4446

4547
@staticmethod
46-
def _get_services_at_runtime():
48+
def _get_services_at_runtime() -> set[ServiceName]:
4749
from localstack.services.plugins import SERVICE_PLUGINS
4850

4951
return set(SERVICE_PLUGINS.list_available())
5052

5153
@staticmethod
52-
def _get_cfn_resources_available_at_runtime():
54+
def _get_cfn_resources_available_at_runtime() -> set[CfnResourceName]:
5355
return set(cfn_plugin_manager.list_names())
5456

5557
@abstractmethod
@@ -84,9 +86,7 @@ class AwsCatalogRemoteStatePlugin(CatalogPlugin):
8486
current_emulator_type: LocalstackEmulatorType = LocalstackEmulatorType.COMMUNITY
8587
services_in_latest: dict[ServiceName, dict[LocalstackEmulatorType, ServiceOperations]] = {}
8688
services_at_runtime: set[ServiceName] = set()
87-
cfn_resources_in_latest: dict[
88-
LocalstackEmulatorType, dict[CfnResourceName, set[CfnResourceMethodName]]
89-
] = {}
89+
cfn_resources_in_latest: CfnResourceCatalog = {}
9090
cfn_resources_at_runtime: set[CfnResourceName] = set()
9191

9292
def __init__(self, remote_catalog_loader: RemoteCatalogLoader | None = None) -> None:
@@ -125,7 +125,7 @@ def get_aws_service_status(
125125
return AwsServiceOperationsSupportInLatest.NOT_SUPPORTED
126126

127127
def get_cloudformation_resource_status(
128-
self, resource_name: str, service_name: str
128+
self, resource_name: str, service_name: str, is_pro_resource: bool = False
129129
) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None:
130130
if resource_name in self.cfn_resources_at_runtime:
131131
return CloudFormationResourcesSupportAtRuntime.AVAILABLE

tests/unit/utils/test_catalog.py

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
from localstack.utils.catalog.catalog_loader import RemoteCatalogLoader
55
from localstack.utils.catalog.common import (
66
AwsRemoteCatalog,
7+
AwsServiceCatalog,
78
AwsServiceOperationsSupportInLatest,
89
AwsServicesSupportInLatest,
10+
CloudFormationResource,
911
CloudFormationResourcesSupportAtRuntime,
1012
CloudFormationResourcesSupportInLatest,
13+
LocalstackEmulatorType,
1114
LocalStackMetadata,
1215
)
1316

@@ -25,35 +28,42 @@ def get_remote_catalog(self) -> AwsRemoteCatalog:
2528
localstack=LocalStackMetadata(version="4.7"),
2629
services={
2730
"athena": {
28-
"pro": {
29-
"provider": "athena:pro",
30-
"operations": ["StartQueryExecution", "GetQueryExecution"],
31-
"plans": ["ultimate", "enterprise"],
32-
}
31+
"pro": AwsServiceCatalog(
32+
provider="athena:pro",
33+
operations=["StartQueryExecution", "GetQueryExecution"],
34+
plans=["ultimate", "enterprise"],
35+
)
3336
},
3437
"s3": {
35-
"community": {
36-
"provider": "s3:default",
37-
"operations": ["CreateBucket"],
38-
"plans": ["free", "base", "ultimate", "enterprise"],
39-
},
40-
"pro": {
41-
"provider": "s3:pro",
42-
"operations": ["SelectObjectContent"],
43-
"plans": ["base", "ultimate", "enterprise"],
44-
},
38+
"community": AwsServiceCatalog(
39+
provider="s3:default",
40+
operations=["CreateBucket"],
41+
plans=["free", "base", "ultimate", "enterprise"],
42+
),
43+
"pro": AwsServiceCatalog(
44+
provider="s3:pro",
45+
operations=["SelectObjectContent"],
46+
plans=["base", "ultimate", "enterprise"],
47+
),
4548
},
4649
"kms": {
47-
"community": {
48-
"provider": "kms:default",
49-
"operations": ["ListKeys"],
50-
"plans": ["free", "base", "ultimate", "enterprise"],
51-
}
50+
"community": AwsServiceCatalog(
51+
provider="kms:default",
52+
operations=["ListKeys"],
53+
plans=["free", "base", "ultimate", "enterprise"],
54+
)
5255
},
5356
},
5457
cloudformation_resources={
55-
"community": {"AWS::S3::Bucket": {"methods": ["Create", "Delete"]}},
56-
"pro": {"AWS::Athena::CapacitiesReservation": {"methods": ["Create", "Update", "Delete"]}},
58+
"community": {
59+
"AWS::S3::Bucket": CloudFormationResource(methods=["Create", "Delete"]),
60+
"AWS::KMS::Key": CloudFormationResource(methods=["Create", "Delete"]),
61+
},
62+
"pro": {
63+
"AWS::Athena::CapacitiesReservation": CloudFormationResource(
64+
methods=["Create", "Update", "Delete"]
65+
),
66+
},
5767
},
5868
)
5969

@@ -129,3 +139,10 @@ def test_get_cfn_resource_status(
129139
):
130140
result = aws_catalog.get_cloudformation_resource_status(resource_name, service_name)
131141
assert result == expected_status
142+
143+
def test_build_cfn_catalog_resources(self, aws_catalog):
144+
community_resources = aws_catalog.cfn_resources_in_latest[LocalstackEmulatorType.COMMUNITY]
145+
assert set(community_resources) == {"AWS::S3::Bucket", "AWS::KMS::Key"}
146+
147+
pro_resources = aws_catalog.cfn_resources_in_latest[LocalstackEmulatorType.PRO]
148+
assert set(pro_resources) == {"AWS::Athena::CapacitiesReservation"}

0 commit comments

Comments
 (0)