Skip to content

Commit ec9552c

Browse files
mckev-amazonlaurenyu
authored andcommitted
Prepend SageMaker Notebook Instance version ID to boto3 User Agent (#600)
SageMaker Notebook Instances provide the version ID as a file on a Notebook Instance. In order to enhance version adoption from within SageMaker, provide an extra segment to the user_agent supplied to the boto3 ClientConfig. Added new unit tests: * Basic test to verify User Agent propagation * Test to ensure that notebook instance is injected * Test to ensure handling of the IOError when reading the file.
1 parent 819a980 commit ec9552c

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ CHANGELOG
33
=========
44

55

6+
1.18.2.dev
7+
======
8+
* enhancement: Include SageMaker Notebook Instance version number in boto3 user agent, if available.
9+
610
1.18.1
711
======
812

src/sagemaker/user_agent.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,23 @@
2525
PYTHON_VERSION = '{}.{}.{}'.format(sys.version_info.major, sys.version_info.minor, sys.version_info.micro)
2626

2727

28-
def prepend_user_agent(client):
28+
def determine_prefix():
2929
prefix = 'AWS-SageMaker-Python-SDK/{} Python/{} {}/{} Boto3/{} Botocore/{}'\
3030
.format(SDK_VERSION, PYTHON_VERSION, OS_NAME, OS_VERSION, boto3.__version__, botocore.__version__)
31+
32+
try:
33+
with open('/etc/opt/ml/sagemaker-notebook-instance-version.txt') as sagemaker_nbi_file:
34+
prefix = 'AWS-SageMaker-Notebook-Instance/{} {}'.format(sagemaker_nbi_file.read().strip(), prefix)
35+
except IOError:
36+
# This file isn't expected to always exist, and we DO want to silently ignore failures.
37+
pass
38+
39+
return prefix
40+
41+
42+
def prepend_user_agent(client):
43+
prefix = determine_prefix()
44+
3145
if client._client_config.user_agent is None:
3246
client._client_config.user_agent = prefix
3347
else:

tests/unit/test_session.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import pytest
2020
import six
2121
from botocore.exceptions import ClientError
22-
from mock import Mock, patch, call
22+
from mock import MagicMock, Mock, patch, call, mock_open
2323

2424
import sagemaker
2525
from sagemaker import s3_input, Session, get_execution_role
@@ -36,6 +36,12 @@
3636
@pytest.fixture()
3737
def boto_session():
3838
boto_session = Mock(region_name=REGION)
39+
40+
mock_client = Mock()
41+
mock_client._client_config.user_agent = \
42+
'Boto3/1.9.69 Python/3.6.5 Linux/4.14.77-70.82.amzn1.x86_64 Botocore/1.12.69 Resource'
43+
44+
boto_session.client.return_value = mock_client
3945
return boto_session
4046

4147

@@ -139,6 +145,45 @@ def test_delete_endpoint(boto_session):
139145
boto_session.client().delete_endpoint.assert_called_with(EndpointName='my_endpoint')
140146

141147

148+
def test_user_agent_injected(boto_session):
149+
assert 'AWS-SageMaker-Python-SDK' not in boto_session.client('sagemaker')._client_config.user_agent
150+
151+
sess = Session(boto_session)
152+
153+
assert 'AWS-SageMaker-Python-SDK' in sess.sagemaker_client._client_config.user_agent
154+
assert 'AWS-SageMaker-Python-SDK' in sess.sagemaker_runtime_client._client_config.user_agent
155+
assert 'AWS-SageMaker-Notebook-Instance' not in sess.sagemaker_client._client_config.user_agent
156+
assert 'AWS-SageMaker-Notebook-Instance' not in sess.sagemaker_runtime_client._client_config.user_agent
157+
158+
159+
def test_user_agent_injected_with_nbi(boto_session):
160+
assert 'AWS-SageMaker-Python-SDK' not in boto_session.client('sagemaker')._client_config.user_agent
161+
162+
with patch('six.moves.builtins.open', mock_open(read_data='120.0-0')) as mo:
163+
sess = Session(boto_session)
164+
165+
mo.assert_called_with('/etc/opt/ml/sagemaker-notebook-instance-version.txt')
166+
167+
assert 'AWS-SageMaker-Python-SDK' in sess.sagemaker_client._client_config.user_agent
168+
assert 'AWS-SageMaker-Python-SDK' in sess.sagemaker_runtime_client._client_config.user_agent
169+
assert 'AWS-SageMaker-Notebook-Instance' in sess.sagemaker_client._client_config.user_agent
170+
assert 'AWS-SageMaker-Notebook-Instance' in sess.sagemaker_runtime_client._client_config.user_agent
171+
172+
173+
def test_user_agent_injected_with_nbi_ioerror(boto_session):
174+
assert 'AWS-SageMaker-Python-SDK' not in boto_session.client('sagemaker')._client_config.user_agent
175+
176+
with patch('six.moves.builtins.open', MagicMock(side_effect=IOError('File not found'))) as mo:
177+
sess = Session(boto_session)
178+
179+
mo.assert_called_with('/etc/opt/ml/sagemaker-notebook-instance-version.txt')
180+
181+
assert 'AWS-SageMaker-Python-SDK' in sess.sagemaker_client._client_config.user_agent
182+
assert 'AWS-SageMaker-Python-SDK' in sess.sagemaker_runtime_client._client_config.user_agent
183+
assert 'AWS-SageMaker-Notebook-Instance' not in sess.sagemaker_client._client_config.user_agent
184+
assert 'AWS-SageMaker-Notebook-Instance' not in sess.sagemaker_runtime_client._client_config.user_agent
185+
186+
142187
def test_s3_input_all_defaults():
143188
prefix = 'pre'
144189
actual = s3_input(s3_data=prefix)

0 commit comments

Comments
 (0)