Skip to content

Commit 48c64bc

Browse files
authored
Always use SessionProxy (aws-cloudformation#71)
1 parent f195602 commit 48c64bc

File tree

14 files changed

+519
-403
lines changed

14 files changed

+519
-403
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ repos:
7272
--cov-report=html
7373
--cov="rpdk.python"
7474
--cov="cloudformation_cli_python_lib"
75+
--durations=5
7576
"tests/"
7677
language: system
7778
# ignore all files, run on hard-coded modules instead

setup.cfg

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ max-complexity = 10
1717
max-line-length = 88
1818
select = C,E,F,W,B,B950
1919
# C812, C815, W503 clash with black, F723 false positive
20-
ignore = E501,C812,C815,W503,F723
20+
ignore = E501,C812,C815,C816,W503,F723
2121

2222
[isort]
2323
line_length = 88
@@ -28,6 +28,7 @@ skip = env
2828
include_trailing_comma = true
2929
combine_as_imports = True
3030
force_grid_wrap = 0
31+
known_standard_library = dataclasses
3132
known_first_party = rpdk
3233
known_third_party = boto3,jinja2,cloudformation_cli_python_lib,pytest
3334

src/cloudformation_cli_python_lib/callback.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,15 @@
33
from typing import Optional
44
from uuid import uuid4
55

6-
# boto3 doesn't have stub files
7-
from boto3 import Session # type: ignore
8-
6+
from .boto3_proxy import SessionProxy
97
from .interface import BaseResourceModel, HandlerErrorCode, OperationStatus
108
from .utils import KitchenSinkEncoder
119

1210
LOG = logging.getLogger(__name__)
1311

1412

1513
def report_progress( # pylint: disable=too-many-arguments
16-
session: Session,
14+
session: SessionProxy,
1715
bearer_token: str,
1816
error_code: Optional[HandlerErrorCode],
1917
operation_status: OperationStatus,

src/cloudformation_cli_python_lib/log_delivery.py

Lines changed: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,28 @@
11
import logging
22
import time
3-
from typing import Any, Mapping, Optional
3+
from typing import Any, Optional
44

5-
# boto3 doesn't have stub files
6-
import boto3 # type: ignore
5+
from .boto3_proxy import SessionProxy
6+
from .utils import HandlerRequest
77

88

99
class ProviderFilter(logging.Filter):
10-
PROVIDER = ""
10+
def __init__(self, provider: str):
11+
super().__init__()
12+
self.provider = provider
1113

1214
def filter(self, record: logging.LogRecord) -> bool:
13-
return not record.name.startswith(self.PROVIDER)
15+
return not record.name.startswith(self.provider)
1416

1517

1618
class ProviderLogHandler(logging.Handler):
1719
def __init__(
18-
self,
19-
group: str,
20-
stream: str,
21-
creds: Mapping[str, str],
22-
*args: Any,
23-
**kwargs: Any,
20+
self, group: str, stream: str, session: SessionProxy, *args: Any, **kwargs: Any
2421
):
2522
super(ProviderLogHandler, self).__init__(*args, **kwargs)
2623
self.group = group
2724
self.stream = stream.replace(":", "__")
28-
self.client = boto3.client("logs", **creds)
25+
self.client = session.client("logs")
2926
self.sequence_token = ""
3027

3128
@classmethod
@@ -36,48 +33,27 @@ def _get_existing_logger(cls) -> Optional["ProviderLogHandler"]:
3633
return None
3734

3835
@classmethod
39-
def setup(cls, event_data: Mapping[str, Any]) -> None:
40-
try:
41-
log_creds = event_data["requestData"]["providerCredentials"]
42-
except KeyError:
43-
log_creds = {}
44-
try:
45-
log_group = event_data["requestData"]["providerLogGroupName"]
46-
except KeyError:
47-
log_group = ""
48-
try:
49-
stream_name = (
50-
f'{event_data["stackId"]}/'
51-
f'{event_data["requestData"]["logicalResourceId"]}'
52-
)
53-
except KeyError:
54-
stream_name = f'{event_data["awsAccountId"]}-{event_data["region"]}'
36+
def setup(
37+
cls, request: HandlerRequest, provider_sess: Optional[SessionProxy]
38+
) -> None:
39+
log_group = request.requestData.providerLogGroupName
40+
if request.stackId and request.requestData.logicalResourceId:
41+
stream_name = f"{request.stackId}/{request.requestData.logicalResourceId}"
42+
else:
43+
stream_name = f"{request.awsAccountId}-{request.region}"
5544

5645
log_handler = cls._get_existing_logger()
57-
if log_creds and log_group:
46+
if provider_sess and log_group:
5847
if log_handler:
5948
# This is a re-used lambda container, log handler is already setup, so
6049
# we just refresh the client with new creds
61-
log_handler.client = boto3.client(
62-
"logs",
63-
aws_access_key_id=log_creds["accessKeyId"],
64-
aws_secret_access_key=log_creds["secretAccessKey"],
65-
aws_session_token=log_creds["sessionToken"],
66-
)
50+
log_handler.client = provider_sess.client("logs")
6751
return
6852
# filter provider messages from platform
69-
ProviderFilter.PROVIDER = (
70-
event_data["resourceType"].replace("::", "_").lower()
71-
)
72-
logging.getLogger().handlers[0].addFilter(ProviderFilter())
53+
provider = request.resourceType.replace("::", "_").lower()
54+
logging.getLogger().handlers[0].addFilter(ProviderFilter(provider))
7355
log_handler = cls(
74-
group=log_group,
75-
stream=stream_name,
76-
creds={
77-
"aws_access_key_id": log_creds["accessKeyId"],
78-
"aws_secret_access_key": log_creds["secretAccessKey"],
79-
"aws_session_token": log_creds["sessionToken"],
80-
},
56+
group=log_group, stream=stream_name, session=provider_sess
8157
)
8258
# add log handler to root, so that provider gets plugin logs too
8359
logging.getLogger().addHandler(log_handler)

src/cloudformation_cli_python_lib/metrics.py

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import datetime
22
import logging
3-
from typing import Any, List, Mapping
4-
5-
# boto3 doesn't have stub files
6-
from boto3.session import Session # type: ignore
3+
from typing import Any, List, Mapping, Optional
74

85
from botocore.exceptions import ClientError # type: ignore
96

7+
from .boto3_proxy import SessionProxy
108
from .interface import Action, MetricTypes, StandardUnit
119

1210
LOG = logging.getLogger(__name__)
@@ -19,11 +17,9 @@ def format_dimensions(dimensions: Mapping[str, str]) -> List[Mapping[str, str]]:
1917

2018

2119
class MetricPublisher:
22-
def __init__(self, account_id: str, resource_type: str, session: Session) -> None:
23-
suffix = resource_type.replace("::", "/")
24-
self.namespace = f"{METRIC_NAMESPACE_ROOT}/{account_id}/{suffix}"
25-
self.resource_type = resource_type
20+
def __init__(self, session: SessionProxy, namespace: str) -> None:
2621
self.client = session.client("cloudwatch")
22+
self.namespace = namespace
2723

2824
def publish_metric( # pylint: disable-msg=too-many-arguments
2925
self,
@@ -52,21 +48,29 @@ def publish_metric( # pylint: disable-msg=too-many-arguments
5248

5349

5450
class MetricsPublisherProxy:
55-
def __init__(self) -> None:
51+
@staticmethod
52+
def _make_namespace(account_id: str, resource_type: str) -> str:
53+
suffix = resource_type.replace("::", "/")
54+
return f"{METRIC_NAMESPACE_ROOT}/{account_id}/{suffix}"
55+
56+
def __init__(self, account_id: str, resource_type: str) -> None:
57+
self.namespace = self._make_namespace(account_id, resource_type)
58+
self.resource_type = resource_type
5659
self._publishers: List[MetricPublisher] = []
5760

58-
def add_metrics_publisher(self, publisher: MetricPublisher) -> None:
59-
self._publishers.append(publisher)
61+
def add_metrics_publisher(self, session: Optional[SessionProxy]) -> None:
62+
if session:
63+
self._publishers.append(MetricPublisher(session, self.namespace))
6064

6165
def publish_exception_metric(
6266
self, timestamp: datetime.datetime, action: Action, error: Any
6367
) -> None:
68+
dimensions: Mapping[str, str] = {
69+
"DimensionKeyActionType": action.name,
70+
"DimensionKeyExceptionType": str(type(error)),
71+
"DimensionKeyResourceType": self.resource_type,
72+
}
6473
for publisher in self._publishers:
65-
dimensions: Mapping[str, str] = {
66-
"DimensionKeyActionType": action.name,
67-
"DimensionKeyExceptionType": str(type(error)),
68-
"DimensionKeyResourceType": publisher.resource_type,
69-
}
7074
publisher.publish_metric(
7175
metric_name=MetricTypes.HandlerException,
7276
dimensions=dimensions,
@@ -78,11 +82,11 @@ def publish_exception_metric(
7882
def publish_invocation_metric(
7983
self, timestamp: datetime.datetime, action: Action
8084
) -> None:
85+
dimensions = {
86+
"DimensionKeyActionType": action.name,
87+
"DimensionKeyResourceType": self.resource_type,
88+
}
8189
for publisher in self._publishers:
82-
dimensions = {
83-
"DimensionKeyActionType": action.name,
84-
"DimensionKeyResourceType": publisher.resource_type,
85-
}
8690
publisher.publish_metric(
8791
metric_name=MetricTypes.HandlerInvocationCount,
8892
dimensions=dimensions,
@@ -94,11 +98,11 @@ def publish_invocation_metric(
9498
def publish_duration_metric(
9599
self, timestamp: datetime.datetime, action: Action, milliseconds: float
96100
) -> None:
101+
dimensions = {
102+
"DimensionKeyActionType": action.name,
103+
"DimensionKeyResourceType": self.resource_type,
104+
}
97105
for publisher in self._publishers:
98-
dimensions = {
99-
"DimensionKeyActionType": action.name,
100-
"DimensionKeyResourceType": publisher.resource_type,
101-
}
102106
publisher.publish_metric(
103107
metric_name=MetricTypes.HandlerInvocationDuration,
104108
dimensions=dimensions,
@@ -110,12 +114,12 @@ def publish_duration_metric(
110114
def publish_log_delivery_exception_metric(
111115
self, timestamp: datetime.datetime, error: Any
112116
) -> None:
117+
dimensions = {
118+
"DimensionKeyActionType": "ProviderLogDelivery",
119+
"DimensionKeyExceptionType": str(type(error)),
120+
"DimensionKeyResourceType": self.resource_type,
121+
}
113122
for publisher in self._publishers:
114-
dimensions: Mapping[str, str] = {
115-
"DimensionKeyActionType": "ProviderLogDelivery",
116-
"DimensionKeyExceptionType": str(type(error)),
117-
"DimensionKeyResourceType": publisher.resource_type,
118-
}
119123
publisher.publish_metric(
120124
metric_name=MetricTypes.HandlerException,
121125
dimensions=dimensions,

0 commit comments

Comments
 (0)