Skip to content

Commit 3859bc7

Browse files
committed
impl
1 parent cdd044b commit 3859bc7

15 files changed

+990
-0
lines changed

aws_lambda_powertools/event_handler/async_execution/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class RouteNotFoundError(Exception):
2+
pass
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING, Any, Callable
4+
5+
from .routes.aws_config_rule import AwsConfigRuleRoute
6+
from .routes.cloud_watch_alarm import CloudWatchAlarmRoute
7+
from .routes.cloud_watch_logs import CloudWatchLogsRoute
8+
from .routes.code_deploy_lifecycle_hook import CodeDeployLifecycleHookRoute
9+
from .routes.event_bridge import EventBridgeRoute
10+
from .routes.s3 import S3Route
11+
from .routes.secrets_manager import SecretsManagerRoute
12+
from .routes.ses import SESRoute
13+
from .routes.sns import SNSRoute
14+
15+
if TYPE_CHECKING:
16+
from .routes.base import BaseRoute
17+
18+
19+
class Router:
20+
_routes: list[BaseRoute]
21+
22+
def __init__(self):
23+
self._routes = []
24+
25+
def aws_config_rule(
26+
self,
27+
arn: str | None = None,
28+
rule_name: str | None = None,
29+
rule_name_prefix: str | None = None,
30+
rule_id: str | None = None,
31+
) -> Callable:
32+
def wrapper_aws_config_rule(func: Callable):
33+
self._routes.append(
34+
AwsConfigRuleRoute(
35+
func=func,
36+
arn=arn,
37+
rule_name=rule_name,
38+
rule_name_prefix=rule_name_prefix,
39+
rule_id=rule_id,
40+
),
41+
)
42+
43+
return wrapper_aws_config_rule
44+
45+
def cloud_watch_alarm(
46+
self,
47+
arn: str | None = None,
48+
alarm_name: str | None = None,
49+
alarm_name_prefix: str | None = None,
50+
) -> Callable:
51+
def wrapper_cloud_watch_alarm(func: Callable):
52+
self._routes.append(
53+
CloudWatchAlarmRoute(func=func, arn=arn, alarm_name=alarm_name, alarm_name_prefix=alarm_name_prefix),
54+
)
55+
56+
return wrapper_cloud_watch_alarm
57+
58+
def cloud_watch_logs(
59+
self,
60+
log_group: str | None = None,
61+
log_group_prefix: str | None = None,
62+
log_stream: str | None = None,
63+
log_stream_prefix: str | None = None,
64+
subscription_filters: str | list[str] | None = None,
65+
) -> Callable:
66+
def wrapper_cloud_watch_logs(func: Callable):
67+
self._routes.append(
68+
CloudWatchLogsRoute(
69+
func=func,
70+
log_group=log_group,
71+
log_group_prefix=log_group_prefix,
72+
log_stream=log_stream,
73+
log_stream_prefix=log_stream_prefix,
74+
subscription_filters=subscription_filters,
75+
),
76+
)
77+
78+
return wrapper_cloud_watch_logs
79+
80+
def code_deploy_lifecycle_hook(self) -> Callable:
81+
def wrapper_code_deploy_lifecycle_hook(func: Callable):
82+
self._routes.append(CodeDeployLifecycleHookRoute(func=func))
83+
84+
return wrapper_code_deploy_lifecycle_hook
85+
86+
def event_bridge(
87+
self,
88+
detail_type: str | None = None,
89+
source: str | None = None,
90+
resources: str | list[str] | None = None,
91+
) -> Callable:
92+
def wrap_event_bridge(func: Callable):
93+
self._routes.append(
94+
EventBridgeRoute(func=func, detail_type=detail_type, source=source, resources=resources),
95+
)
96+
97+
return wrap_event_bridge
98+
99+
def s3(
100+
self,
101+
bucket: str | None = None,
102+
bucket_prefix: str | None = None,
103+
key: str | None = None,
104+
key_prefix: str | None = None,
105+
key_suffix: str | None = None,
106+
event_name: str | None = None,
107+
) -> Callable:
108+
def wrap_s3(func: Callable):
109+
self._routes.append(
110+
S3Route(
111+
func=func,
112+
bucket=bucket,
113+
bucket_prefix=bucket_prefix,
114+
key=key,
115+
key_prefix=key_prefix,
116+
key_suffix=key_suffix,
117+
event_name=event_name,
118+
),
119+
)
120+
121+
return wrap_s3
122+
123+
def secrets_manager(self, secret_id: str | None = None, secret_name_prefix: str | None = None):
124+
def wrap_secrets_manager(func: Callable):
125+
self._routes.append(
126+
SecretsManagerRoute(func=func, secret_id=secret_id, secret_name_prefix=secret_name_prefix),
127+
)
128+
129+
return wrap_secrets_manager
130+
131+
def ses(
132+
self,
133+
mail_to: str | list[str] | None = None,
134+
mail_from: str | list[str] | None = None,
135+
mail_subject: str | None = None,
136+
) -> Callable:
137+
def wrap_ses(func: Callable):
138+
self._routes.append(SESRoute(func=func, mail_to=mail_to, mail_from=mail_from, mail_subject=mail_subject))
139+
140+
return wrap_ses
141+
142+
def sns(
143+
self,
144+
arn: str | None = None,
145+
name: str | None = None,
146+
name_prefix: str | None = None,
147+
subject: str | None = None,
148+
subject_prefix: str | None = None,
149+
) -> Callable:
150+
def wrap_sns(func: Callable):
151+
self._routes.append(
152+
SNSRoute(
153+
func=func,
154+
arn=arn,
155+
name=name,
156+
name_prefix=name_prefix,
157+
subject=subject,
158+
subject_prefix=subject_prefix,
159+
),
160+
)
161+
162+
return wrap_sns
163+
164+
def resolve_route(self, event: dict[str, Any]) -> tuple[Callable, Any] | None:
165+
for route in self._routes:
166+
data = route.match(event=event)
167+
if data is not None:
168+
return data
169+
return None

aws_lambda_powertools/event_handler/async_execution/routes/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from __future__ import annotations
2+
3+
from typing import Any, Callable
4+
5+
from aws_lambda_powertools.utilities.data_classes.aws_config_rule_event import (
6+
AWSConfigRuleEvent,
7+
)
8+
9+
from .base import BaseRoute
10+
11+
12+
class AwsConfigRuleRoute(BaseRoute):
13+
arn: str | None
14+
rule_name: str | None
15+
rule_name_prefix: str | None
16+
rule_id: str | None
17+
18+
def __init__(
19+
self,
20+
func: Callable,
21+
arn: str | None = None,
22+
rule_name: str | None = None,
23+
rule_name_prefix: str | None = None,
24+
rule_id: str | None = None,
25+
):
26+
self.func = func
27+
self.arn = arn
28+
self.rule_name = rule_name
29+
self.rule_name_prefix = rule_name_prefix
30+
self.rule_id = rule_id
31+
32+
if not self.arn and not self.rule_name and not self.rule_name_prefix and not self.rule_id:
33+
raise ValueError("arn, rule_name, rule_name_prefix, or rule_id must be not null")
34+
35+
def match(self, event: dict[str, Any]) -> tuple[Callable, AWSConfigRuleEvent] | None:
36+
if self.arn and event.get("configRuleArn") == self.arn:
37+
return self.func, AWSConfigRuleEvent(event)
38+
elif self.rule_name and event.get("configRuleName") == self.rule_name:
39+
return self.func, AWSConfigRuleEvent(event)
40+
elif self.rule_name_prefix and event.get("configRuleName", "").find(self.rule_name_prefix) == 0:
41+
return self.func, AWSConfigRuleEvent(event)
42+
elif self.rule_id and event.get("configRuleId") == self.rule_id:
43+
return self.func, AWSConfigRuleEvent(event)
44+
else:
45+
return None
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from __future__ import annotations
2+
3+
from abc import ABC, abstractmethod
4+
from typing import Any, Callable
5+
6+
7+
class BaseRoute(ABC):
8+
func: Callable
9+
10+
@abstractmethod
11+
def match(self, event: dict[str, Any]) -> tuple[Callable, Any] | None:
12+
raise NotImplementedError()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from __future__ import annotations
2+
3+
from typing import Any, Callable
4+
5+
from aws_lambda_powertools.utilities.data_classes.cloud_watch_alarm_event import (
6+
CloudWatchAlarmEvent,
7+
)
8+
9+
from .base import BaseRoute
10+
11+
12+
class CloudWatchAlarmRoute(BaseRoute):
13+
arn: str | None
14+
alarm_name: str | None
15+
alarm_name_prefix: str | None
16+
17+
def __init__(
18+
self,
19+
func: Callable,
20+
arn: str | None = None,
21+
alarm_name: str | None = None,
22+
alarm_name_prefix: str | None = None,
23+
):
24+
self.func = func
25+
self.arn = arn
26+
self.alarm_name = alarm_name
27+
self.alarm_name_prefix = alarm_name_prefix
28+
29+
if not self.arn and not self.alarm_name and not self.alarm_name_prefix:
30+
raise ValueError("arn, alarm_name, or alarm_name_prefix must be not null")
31+
32+
def match(self, event: dict[str, Any]) -> tuple[Callable, CloudWatchAlarmEvent] | None:
33+
if self.arn and event.get("alarmArn") == self.arn:
34+
return self.func, CloudWatchAlarmEvent(event)
35+
36+
alarm_name = event.get("alarmData", {}).get("alarmName", "")
37+
if self.alarm_name and alarm_name == self.alarm_name:
38+
return self.func, CloudWatchAlarmEvent(event)
39+
elif self.alarm_name_prefix and alarm_name.find(self.alarm_name_prefix) == 0:
40+
return self.func, CloudWatchAlarmEvent(event)
41+
else:
42+
return None

0 commit comments

Comments
 (0)