Skip to content

Commit 3dc2295

Browse files
Reference data event bus through SSM parameter
1 parent 847e3c9 commit 3dc2295

File tree

6 files changed

+75
-15
lines changed

6 files changed

+75
-15
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from aws_cdk.aws_events import EventBus
2+
from aws_cdk.aws_ssm import StringParameter
3+
from constructs import Construct
4+
5+
DATA_EVENT_BUS_ARN_SSM_PARAMETER_NAME = '/deployment/event-bridge/event-bus/data-event-bus-arn'
6+
7+
8+
class SSMParameterUtility:
9+
"""
10+
Utility class for SSM parameter operations.
11+
12+
This class provides static methods for common SSM parameter operations,
13+
such as loading resources from SSM parameters to bypass cross-stack references.
14+
"""
15+
16+
@staticmethod
17+
def load_data_event_bus_from_ssm_parameter(scope: Construct) -> EventBus:
18+
"""
19+
Load the data event bus from an SSM parameter.
20+
21+
This pattern breaks cross-stack references by storing and retrieving
22+
the event bus ARN in SSM Parameter Store rather than using a direct reference,
23+
which helps avoid issues with CloudFormation stack updates.
24+
25+
Args:
26+
scope: The CDK construct scope
27+
28+
Returns:
29+
The EventBus construct
30+
"""
31+
data_event_bus_arn = StringParameter.from_string_parameter_name(
32+
scope,
33+
'DataEventBusArnParameter',
34+
string_parameter_name=DATA_EVENT_BUS_ARN_SSM_PARAMETER_NAME,
35+
)
36+
37+
return EventBus.from_event_bus_arn(scope, 'DataEventBus', event_bus_arn=data_event_bus_arn.string_value)

backend/compact-connect/stacks/api_stack/v1_api/query_providers.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from cdk_nag import NagSuppressions
2020
from common_constructs.nodejs_function import NodejsFunction
2121
from common_constructs.python_function import PythonFunction
22+
from common_constructs.ssm_parameter_utility import SSMParameterUtility
2223
from common_constructs.stack import Stack
2324

2425
from stacks import persistent_stack as ps
@@ -48,13 +49,17 @@ def __init__(
4849
self.api_model = api_model
4950

5051
stack: Stack = Stack.of(resource)
52+
53+
# Load the data event bus from SSM parameter instead of direct reference
54+
data_event_bus = SSMParameterUtility.load_data_event_bus_from_ssm_parameter(stack)
55+
5156
lambda_environment = {
5257
'PROVIDER_TABLE_NAME': persistent_stack.provider_table.table_name,
5358
'PROV_FAM_GIV_MID_INDEX_NAME': persistent_stack.provider_table.provider_fam_giv_mid_index_name,
5459
'PROV_DATE_OF_UPDATE_INDEX_NAME': persistent_stack.provider_table.provider_date_of_update_index_name,
5560
'SSN_TABLE_NAME': persistent_stack.ssn_table.table_name,
5661
'SSN_INDEX_NAME': persistent_stack.ssn_table.ssn_index_name,
57-
'EVENT_BUS_NAME': persistent_stack.data_event_bus.event_bus_name,
62+
'EVENT_BUS_NAME': data_event_bus.event_bus_name,
5863
'RATE_LIMITING_TABLE_NAME': persistent_stack.rate_limiting_table.table_name,
5964
'USER_POOL_ID': persistent_stack.staff_users.user_pool_id,
6065
'EMAIL_NOTIFICATION_SERVICE_LAMBDA_NAME': persistent_stack.email_notification_service_lambda.function_name,
@@ -85,7 +90,7 @@ def __init__(
8590
self._add_deactivate_privilege(
8691
method_options=admin_method_options,
8792
provider_data_table=persistent_stack.provider_table,
88-
event_bus=persistent_stack.data_event_bus,
93+
event_bus=data_event_bus,
8994
email_service_lambda=persistent_stack.email_notification_service_lambda,
9095
staff_users_table=persistent_stack.staff_users.user_table,
9196
lambda_environment=lambda_environment,

backend/compact-connect/stacks/ingest_stack.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
from aws_cdk import Duration
66
from aws_cdk.aws_cloudwatch import Alarm, ComparisonOperator, Metric, Stats, TreatMissingData
77
from aws_cdk.aws_cloudwatch_actions import SnsAction
8-
from aws_cdk.aws_events import EventPattern, Rule
8+
from aws_cdk.aws_events import EventBus, EventPattern, Rule
99
from aws_cdk.aws_events_targets import SqsQueue
1010
from cdk_nag import NagSuppressions
1111
from common_constructs.python_function import PythonFunction
1212
from common_constructs.queued_lambda_processor import QueuedLambdaProcessor
13+
from common_constructs.ssm_parameter_utility import SSMParameterUtility
1314
from common_constructs.stack import AppStack, Stack
1415
from constructs import Construct
1516

@@ -27,9 +28,11 @@ def __init__(
2728
**kwargs,
2829
):
2930
super().__init__(scope, construct_id, environment_name=environment_name, **kwargs)
30-
self._add_v1_ingest_chain(persistent_stack)
31+
# We explicitly get the event bus arn from parameter store, to avoid issues with cross stack updates
32+
data_event_bus = SSMParameterUtility.load_data_event_bus_from_ssm_parameter(self)
33+
self._add_v1_ingest_chain(persistent_stack, data_event_bus)
3134

32-
def _add_v1_ingest_chain(self, persistent_stack: ps.PersistentStack):
35+
def _add_v1_ingest_chain(self, persistent_stack: ps.PersistentStack, data_event_bus: EventBus):
3336
ingest_handler = PythonFunction(
3437
self,
3538
'V1IngestHandler',
@@ -39,14 +42,14 @@ def _add_v1_ingest_chain(self, persistent_stack: ps.PersistentStack):
3942
handler='ingest_license_message',
4043
timeout=Duration.minutes(1),
4144
environment={
42-
'EVENT_BUS_NAME': persistent_stack.data_event_bus.event_bus_name,
45+
'EVENT_BUS_NAME': data_event_bus.event_bus_name,
4346
'PROVIDER_TABLE_NAME': persistent_stack.provider_table.table_name,
4447
**self.common_env_vars,
4548
},
4649
alarm_topic=persistent_stack.alarm_topic,
4750
)
4851
persistent_stack.provider_table.grant_read_write_data(ingest_handler)
49-
persistent_stack.data_event_bus.grant_put_events_to(ingest_handler)
52+
data_event_bus.grant_put_events_to(ingest_handler)
5053

5154
NagSuppressions.add_resource_suppressions_by_path(
5255
Stack.of(ingest_handler.role),
@@ -90,7 +93,7 @@ def _add_v1_ingest_chain(self, persistent_stack: ps.PersistentStack):
9093
ingest_rule = Rule(
9194
self,
9295
'V1IngestEventRule',
93-
event_bus=persistent_stack.data_event_bus,
96+
event_bus=data_event_bus,
9497
event_pattern=EventPattern(detail_type=['license.ingest']),
9598
targets=[SqsQueue(processor.queue, dead_letter_queue=processor.dlq)],
9699
)
@@ -103,7 +106,7 @@ def _add_v1_ingest_chain(self, persistent_stack: ps.PersistentStack):
103106
namespace='AWS/Events',
104107
metric_name='FailedInvocations',
105108
dimensions_map={
106-
'EventBusName': persistent_stack.data_event_bus.event_bus_name,
109+
'EventBusName': data_event_bus.event_bus_name,
107110
'RuleName': ingest_rule.rule_name,
108111
},
109112
period=Duration.minutes(5),

backend/compact-connect/stacks/persistent_stack/__init__.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from common_constructs.nodejs_function import NodejsFunction
1616
from common_constructs.python_function import COMMON_PYTHON_LAMBDA_LAYER_SSM_PARAMETER_NAME
1717
from common_constructs.security_profile import SecurityProfile
18+
from common_constructs.ssm_parameter_utility import DATA_EVENT_BUS_ARN_SSM_PARAMETER_NAME
1819
from common_constructs.stack import AppStack
1920
from constructs import Construct
2021

@@ -106,7 +107,21 @@ def __init__(
106107
auto_delete_objects=removal_policy == RemovalPolicy.DESTROY,
107108
)
108109

109-
self.data_event_bus = EventBus(self, 'DataEventBus')
110+
# This resource should not be reference directly as a cross stack reference, any reference should
111+
# be made through the SSM parameter
112+
self._data_event_bus = EventBus( self, 'DataEventBus')
113+
# We Store the data event bus name in SSM Parameter Store
114+
# to avoid issues with cross stack references due to the fact that
115+
# you can't update a CloudFormation exported value that is being referenced by a resource in another stack.
116+
self.data_event_bus_arn_ssm_parameter = aws_ssm.StringParameter(
117+
self,
118+
'DataEventBusArnParameter',
119+
parameter_name=DATA_EVENT_BUS_ARN_SSM_PARAMETER_NAME,
120+
string_value=self._data_event_bus.event_bus_arn,
121+
)
122+
# TODO - these are needed until pipeline migration effort is complete # noqa: FIX002
123+
self.export_value(self._data_event_bus.event_bus_arn)
124+
self.export_value(self._data_event_bus.event_bus_name)
110125

111126
self._add_data_resources(removal_policy=removal_policy)
112127
self._add_migrations()
@@ -243,7 +258,7 @@ def _add_data_resources(self, removal_policy: RemovalPolicy):
243258
self,
244259
'SSNTable',
245260
removal_policy=removal_policy,
246-
data_event_bus=self.data_event_bus,
261+
data_event_bus=self._data_event_bus,
247262
alarm_topic=self.alarm_topic,
248263
)
249264

@@ -257,7 +272,7 @@ def _add_data_resources(self, removal_policy: RemovalPolicy):
257272
bucket_encryption_key=self.ssn_table.key,
258273
removal_policy=removal_policy,
259274
auto_delete_objects=removal_policy == RemovalPolicy.DESTROY,
260-
event_bus=self.data_event_bus,
275+
event_bus=self._data_event_bus,
261276
license_preprocessing_queue=self.ssn_table.preprocessor_queue.queue,
262277
license_upload_role=self.ssn_table.license_upload_role,
263278
)
@@ -304,7 +319,7 @@ def _add_data_resources(self, removal_policy: RemovalPolicy):
304319
scope=self,
305320
construct_id='DataEventTable',
306321
encryption_key=self.shared_encryption_key,
307-
event_bus=self.data_event_bus,
322+
event_bus=self._data_event_bus,
308323
alarm_topic=self.alarm_topic,
309324
removal_policy=removal_policy,
310325
)

backend/compact-connect/stacks/persistent_stack/data_event_table.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def __init__(
116116
namespace='AWS/Events',
117117
metric_name='FailedInvocations',
118118
dimensions_map={
119-
'EventBusName': stack.data_event_bus.event_bus_name,
119+
'EventBusName': event_bus.event_bus_name,
120120
'RuleName': event_receiver_rule.rule_name,
121121
},
122122
period=Duration.minutes(5),

backend/compact-connect/tests/app/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def _inspect_ssn_table(self, persistent_stack: PersistentStack, persistent_stack
212212

213213
def _inspect_data_events_table(self, persistent_stack: PersistentStack, persistent_stack_template: Template):
214214
# Ensure our DataEventTable and queues are created
215-
event_bus_logical_id = persistent_stack.get_logical_id(persistent_stack.data_event_bus.node.default_child)
215+
event_bus_logical_id = persistent_stack.get_logical_id(persistent_stack._data_event_bus.node.default_child) # noqa: SLF001 private_member_access
216216
queue_logical_id = persistent_stack.get_logical_id(
217217
persistent_stack.data_event_table.event_processor.queue.node.default_child
218218
)

0 commit comments

Comments
 (0)