sagemaker-core 1.0.8__tar.gz → 1.0.10__tar.gz
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.
Potentially problematic release.
This version of sagemaker-core might be problematic. Click here for more details.
- {sagemaker_core-1.0.8/src/sagemaker_core.egg-info → sagemaker_core-1.0.10}/PKG-INFO +1 -1
- sagemaker_core-1.0.10/VERSION +1 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/code_injection/shape_dag.py +18 -0
- sagemaker_core-1.0.10/src/sagemaker_core/main/logs.py +167 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/resources.py +202 -51
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/shapes.py +4 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/utils.py +9 -3
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/tools/constants.py +2 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/tools/resources_codegen.py +47 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/tools/templates.py +42 -6
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10/src/sagemaker_core.egg-info}/PKG-INFO +1 -1
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core.egg-info/SOURCES.txt +1 -0
- sagemaker_core-1.0.8/VERSION +0 -1
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/LICENSE +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/MANIFEST.in +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/README.rst +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/pyproject.toml +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/setup.cfg +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/__init__.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/_version.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/helper/__init__.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/helper/session_helper.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/__init__.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/code_injection/__init__.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/code_injection/base.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/code_injection/codec.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/code_injection/constants.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/config_schema.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/exceptions.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/intelligent_defaults_helper.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/user_agent.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/resources/__init__.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/shapes/__init__.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/tools/__init__.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/tools/codegen.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/tools/data_extractor.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/tools/method.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/tools/resources_extractor.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/tools/shapes_codegen.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/tools/shapes_extractor.py +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core.egg-info/dependency_links.txt +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core.egg-info/requires.txt +0 -0
- {sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.10
|
{sagemaker_core-1.0.8 → sagemaker_core-1.0.10}/src/sagemaker_core/main/code_injection/shape_dag.py
RENAMED
|
@@ -1380,6 +1380,11 @@ SHAPE_DAG = {
|
|
|
1380
1380
|
"shape": "AppLifecycleManagement",
|
|
1381
1381
|
"type": "structure",
|
|
1382
1382
|
},
|
|
1383
|
+
{
|
|
1384
|
+
"name": "BuiltInLifecycleConfigArn",
|
|
1385
|
+
"shape": "StudioLifecycleConfigArn",
|
|
1386
|
+
"type": "string",
|
|
1387
|
+
},
|
|
1383
1388
|
],
|
|
1384
1389
|
"type": "structure",
|
|
1385
1390
|
},
|
|
@@ -1884,6 +1889,7 @@ SHAPE_DAG = {
|
|
|
1884
1889
|
"shape": "AppSecurityGroupManagement",
|
|
1885
1890
|
"type": "string",
|
|
1886
1891
|
},
|
|
1892
|
+
{"name": "TagPropagation", "shape": "TagPropagation", "type": "string"},
|
|
1887
1893
|
{"name": "DefaultSpaceSettings", "shape": "DefaultSpaceSettings", "type": "structure"},
|
|
1888
1894
|
],
|
|
1889
1895
|
"type": "structure",
|
|
@@ -3792,6 +3798,11 @@ SHAPE_DAG = {
|
|
|
3792
3798
|
{"name": "CreationTime", "shape": "Timestamp", "type": "timestamp"},
|
|
3793
3799
|
{"name": "FailureReason", "shape": "FailureReason", "type": "string"},
|
|
3794
3800
|
{"name": "ResourceSpec", "shape": "ResourceSpec", "type": "structure"},
|
|
3801
|
+
{
|
|
3802
|
+
"name": "BuiltInLifecycleConfigArn",
|
|
3803
|
+
"shape": "StudioLifecycleConfigArn",
|
|
3804
|
+
"type": "string",
|
|
3805
|
+
},
|
|
3795
3806
|
],
|
|
3796
3807
|
"type": "structure",
|
|
3797
3808
|
},
|
|
@@ -4125,6 +4136,7 @@ SHAPE_DAG = {
|
|
|
4125
4136
|
"shape": "AppSecurityGroupManagement",
|
|
4126
4137
|
"type": "string",
|
|
4127
4138
|
},
|
|
4139
|
+
{"name": "TagPropagation", "shape": "TagPropagation", "type": "string"},
|
|
4128
4140
|
{"name": "DefaultSpaceSettings", "shape": "DefaultSpaceSettings", "type": "structure"},
|
|
4129
4141
|
],
|
|
4130
4142
|
"type": "structure",
|
|
@@ -7697,6 +7709,11 @@ SHAPE_DAG = {
|
|
|
7697
7709
|
"type": "structure",
|
|
7698
7710
|
},
|
|
7699
7711
|
{"name": "EmrSettings", "shape": "EmrSettings", "type": "structure"},
|
|
7712
|
+
{
|
|
7713
|
+
"name": "BuiltInLifecycleConfigArn",
|
|
7714
|
+
"shape": "StudioLifecycleConfigArn",
|
|
7715
|
+
"type": "string",
|
|
7716
|
+
},
|
|
7700
7717
|
],
|
|
7701
7718
|
"type": "structure",
|
|
7702
7719
|
},
|
|
@@ -14082,6 +14099,7 @@ SHAPE_DAG = {
|
|
|
14082
14099
|
{"name": "DefaultSpaceSettings", "shape": "DefaultSpaceSettings", "type": "structure"},
|
|
14083
14100
|
{"name": "SubnetIds", "shape": "Subnets", "type": "list"},
|
|
14084
14101
|
{"name": "AppNetworkAccessType", "shape": "AppNetworkAccessType", "type": "string"},
|
|
14102
|
+
{"name": "TagPropagation", "shape": "TagPropagation", "type": "string"},
|
|
14085
14103
|
],
|
|
14086
14104
|
"type": "structure",
|
|
14087
14105
|
},
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import boto3
|
|
2
|
+
import botocore
|
|
3
|
+
|
|
4
|
+
from boto3.session import Session
|
|
5
|
+
import botocore.client
|
|
6
|
+
from botocore.config import Config
|
|
7
|
+
from typing import Generator, Tuple, List
|
|
8
|
+
from sagemaker_core.main.utils import SingletonMeta
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CloudWatchLogsClient(metaclass=SingletonMeta):
|
|
12
|
+
"""
|
|
13
|
+
A singleton class for creating a CloudWatchLogs client.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
client: botocore.client = None
|
|
17
|
+
|
|
18
|
+
def __init__(self):
|
|
19
|
+
if not self.client:
|
|
20
|
+
session = Session()
|
|
21
|
+
self.client = session.client(
|
|
22
|
+
"logs",
|
|
23
|
+
session.region_name,
|
|
24
|
+
config=Config(retries={"max_attempts": 10, "mode": "standard"}),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class LogStreamHandler:
|
|
29
|
+
log_group_name: str = None
|
|
30
|
+
log_stream_name: str = None
|
|
31
|
+
stream_id: int = None
|
|
32
|
+
next_token: str = None
|
|
33
|
+
cw_client = None
|
|
34
|
+
|
|
35
|
+
def __init__(self, log_group_name: str, log_stream_name: str, stream_id: int):
|
|
36
|
+
self.log_group_name = log_group_name
|
|
37
|
+
self.log_stream_name = log_stream_name
|
|
38
|
+
self.cw_client = CloudWatchLogsClient().client
|
|
39
|
+
self.stream_id = stream_id
|
|
40
|
+
|
|
41
|
+
def get_latest_log_events(self) -> Generator[Tuple[str, dict], None, None]:
|
|
42
|
+
"""
|
|
43
|
+
This method gets all the latest log events for this stream that exist at this moment in time.
|
|
44
|
+
|
|
45
|
+
cw_client.get_log_events() always returns a nextForwardToken even if the current batch of events is empty.
|
|
46
|
+
You can keep calling cw_client.get_log_events() with the same token until a new batch of log events exist.
|
|
47
|
+
|
|
48
|
+
API Reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs/client/get_log_events.html
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Generator[tuple[str, dict], None, None]: Generator that yields a tuple that consists for two values
|
|
52
|
+
str: stream_name,
|
|
53
|
+
dict: event dict in format
|
|
54
|
+
{
|
|
55
|
+
"ingestionTime": number,
|
|
56
|
+
"message": "string",
|
|
57
|
+
"timestamp": number
|
|
58
|
+
}
|
|
59
|
+
"""
|
|
60
|
+
while True:
|
|
61
|
+
if not self.next_token:
|
|
62
|
+
token_args = {}
|
|
63
|
+
else:
|
|
64
|
+
token_args = {"nextToken": self.next_token}
|
|
65
|
+
|
|
66
|
+
response = self.cw_client.get_log_events(
|
|
67
|
+
logGroupName=self.log_group_name,
|
|
68
|
+
logStreamName=self.log_stream_name,
|
|
69
|
+
startFromHead=True,
|
|
70
|
+
**token_args,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
self.next_token = response["nextForwardToken"]
|
|
74
|
+
if not response["events"]:
|
|
75
|
+
break
|
|
76
|
+
|
|
77
|
+
for event in response["events"]:
|
|
78
|
+
yield self.log_stream_name, event
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class MultiLogStreamHandler:
|
|
82
|
+
log_group_name: str = None
|
|
83
|
+
log_stream_name_prefix: str = None
|
|
84
|
+
expected_stream_count: int = None
|
|
85
|
+
streams: List[LogStreamHandler] = []
|
|
86
|
+
cw_client = None
|
|
87
|
+
|
|
88
|
+
def __init__(
|
|
89
|
+
self, log_group_name: str, log_stream_name_prefix: str, expected_stream_count: int
|
|
90
|
+
):
|
|
91
|
+
self.log_group_name = log_group_name
|
|
92
|
+
self.log_stream_name_prefix = log_stream_name_prefix
|
|
93
|
+
self.expected_stream_count = expected_stream_count
|
|
94
|
+
self.cw_client = CloudWatchLogsClient().client
|
|
95
|
+
|
|
96
|
+
def get_latest_log_events(self) -> Generator[Tuple[str, dict], None, None]:
|
|
97
|
+
"""
|
|
98
|
+
This method gets all the latest log events from each stream that exist at this moment.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Generator[tuple[str, dict], None, None]: Generator that yields a tuple that consists for two values
|
|
102
|
+
str: stream_name,
|
|
103
|
+
dict: event dict in format -
|
|
104
|
+
{
|
|
105
|
+
"ingestionTime": number,
|
|
106
|
+
"message": "string",
|
|
107
|
+
"timestamp": number
|
|
108
|
+
}
|
|
109
|
+
"""
|
|
110
|
+
if not self.ready():
|
|
111
|
+
return []
|
|
112
|
+
|
|
113
|
+
for stream in self.streams:
|
|
114
|
+
yield from stream.get_latest_log_events()
|
|
115
|
+
|
|
116
|
+
def ready(self) -> bool:
|
|
117
|
+
"""
|
|
118
|
+
Checks whether or not MultiLogStreamHandler is ready to serve new log events at this moment.
|
|
119
|
+
|
|
120
|
+
If self.streams is already set, return True.
|
|
121
|
+
Otherwise, check if the current number of log streams in the log group match the exptected stream count.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
bool: Whether or not MultiLogStreamHandler is ready to serve new log events.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
if len(self.streams) >= self.expected_stream_count:
|
|
128
|
+
return True
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
response = self.cw_client.describe_log_streams(
|
|
132
|
+
logGroupName=self.log_group_name,
|
|
133
|
+
logStreamNamePrefix=self.log_stream_name_prefix + "/",
|
|
134
|
+
orderBy="LogStreamName",
|
|
135
|
+
)
|
|
136
|
+
stream_names = [stream["logStreamName"] for stream in response["logStreams"]]
|
|
137
|
+
|
|
138
|
+
next_token = response.get("nextToken")
|
|
139
|
+
while next_token:
|
|
140
|
+
response = self.cw_client.describe_log_streams(
|
|
141
|
+
logGroupName=self.log_group_name,
|
|
142
|
+
logStreamNamePrefix=self.log_stream_name_prefix + "/",
|
|
143
|
+
orderBy="LogStreamName",
|
|
144
|
+
nextToken=next_token,
|
|
145
|
+
)
|
|
146
|
+
stream_names.extend([stream["logStreamName"] for stream in response["logStreams"]])
|
|
147
|
+
next_token = response.get("nextToken", None)
|
|
148
|
+
|
|
149
|
+
if len(stream_names) >= self.expected_stream_count:
|
|
150
|
+
self.streams = [
|
|
151
|
+
LogStreamHandler(self.log_group_name, log_stream_name, index)
|
|
152
|
+
for index, log_stream_name in enumerate(stream_names)
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
return True
|
|
156
|
+
else:
|
|
157
|
+
# Log streams are created whenever a container starts writing to stdout/err,
|
|
158
|
+
# so if the stream count is less than the expected number, return False
|
|
159
|
+
return False
|
|
160
|
+
|
|
161
|
+
except botocore.exceptions.ClientError as e:
|
|
162
|
+
# On the very first training job run on an account, there's no log group until
|
|
163
|
+
# the container starts logging, so ignore any errors thrown about that
|
|
164
|
+
if e.response["Error"]["Code"] == "ResourceNotFoundException":
|
|
165
|
+
return False
|
|
166
|
+
else:
|
|
167
|
+
raise
|