Skip to content

Commit a65d3f5

Browse files
committed
Merge branch 'master' of github.com:aws/sagemaker-python-sdk into add_tf_2.7_2.8
2 parents e5eefa9 + cbae73f commit a65d3f5

File tree

9 files changed

+229
-7
lines changed

9 files changed

+229
-7
lines changed

doc/overview.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ see `Model <https://sagemaker.readthedocs.io/en/stable/api/inference/model.html
757757
   entry_point="inference.py",
758758
   role=Session().get_caller_identity_arn(),
759759
   predictor_cls=Predictor,
760+
   enable_network_isolation=True,
760761
)
761762
762763
Save the output from deploying the model to a variable named
@@ -874,6 +875,7 @@ value is not set.
874875
    hyperparameters=default_hyperparameters,
875876
    instance_count=instance_count,
876877
    instance_type=training_instance_type,
878+
    enable_network_isolation=True,
877879
)
878880
879881
# Specify the S3 location of training data for the training channel
@@ -935,6 +937,7 @@ took your model to train.
935937
    image_uri=deploy_image_uri,
936938
    source_dir=deploy_script_uri,
937939
    endpoint_name=endpoint_name,
940+
    enable_network_isolation=True,
938941
)
939942
940943
Perform Inference on a SageMaker Endpoint

src/sagemaker/image_uri_config/autogluon.json

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
{
22
"training": {
33
"processors": ["cpu", "gpu"],
4+
"version_aliases": {
5+
"0.3": "0.3.2",
6+
"0.4": "0.4.0"
7+
},
48
"versions": {
59
"0.3.1": {
610
"registries": {
@@ -30,11 +34,73 @@
3034
},
3135
"repository": "autogluon-training",
3236
"py_versions": ["py37"]
37+
},
38+
"0.3.2": {
39+
"registries": {
40+
"af-south-1": "626614931356",
41+
"ap-east-1": "871362719292",
42+
"ap-northeast-1": "763104351884",
43+
"ap-northeast-2": "763104351884",
44+
"ap-northeast-3": "364406365360",
45+
"ap-south-1": "763104351884",
46+
"ap-southeast-1": "763104351884",
47+
"ap-southeast-2": "763104351884",
48+
"ca-central-1": "763104351884",
49+
"eu-central-1": "763104351884",
50+
"eu-north-1": "763104351884",
51+
"eu-west-1": "763104351884",
52+
"eu-west-2": "763104351884",
53+
"eu-west-3": "763104351884",
54+
"eu-south-1": "692866216735",
55+
"me-south-1": "217643126080",
56+
"sa-east-1": "763104351884",
57+
"us-east-1": "763104351884",
58+
"us-east-2": "763104351884",
59+
"us-gov-west-1": "442386744353",
60+
"us-iso-east-1": "886529160074",
61+
"us-west-1": "763104351884",
62+
"us-west-2": "763104351884"
63+
},
64+
"repository": "autogluon-training",
65+
"py_versions": ["py38"]
66+
},
67+
"0.4.0": {
68+
"registries": {
69+
"af-south-1": "626614931356",
70+
"ap-east-1": "871362719292",
71+
"ap-northeast-1": "763104351884",
72+
"ap-northeast-2": "763104351884",
73+
"ap-northeast-3": "364406365360",
74+
"ap-south-1": "763104351884",
75+
"ap-southeast-1": "763104351884",
76+
"ap-southeast-2": "763104351884",
77+
"ca-central-1": "763104351884",
78+
"eu-central-1": "763104351884",
79+
"eu-north-1": "763104351884",
80+
"eu-west-1": "763104351884",
81+
"eu-west-2": "763104351884",
82+
"eu-west-3": "763104351884",
83+
"eu-south-1": "692866216735",
84+
"me-south-1": "217643126080",
85+
"sa-east-1": "763104351884",
86+
"us-east-1": "763104351884",
87+
"us-east-2": "763104351884",
88+
"us-gov-west-1": "442386744353",
89+
"us-iso-east-1": "886529160074",
90+
"us-west-1": "763104351884",
91+
"us-west-2": "763104351884"
92+
},
93+
"repository": "autogluon-training",
94+
"py_versions": ["py38"]
3395
}
3496
}
3597
},
3698
"inference": {
3799
"processors": ["cpu"],
100+
"version_aliases": {
101+
"0.3": "0.3.2",
102+
"0.4": "0.4.0"
103+
},
38104
"versions": {
39105
"0.3.1": {
40106
"registries": {
@@ -66,6 +132,68 @@
66132
},
67133
"repository": "autogluon-inference",
68134
"py_versions": ["py37"]
135+
},
136+
"0.3.2": {
137+
"registries": {
138+
"af-south-1": "626614931356",
139+
"ap-east-1": "871362719292",
140+
"ap-northeast-1": "763104351884",
141+
"ap-northeast-2": "763104351884",
142+
"ap-northeast-3": "364406365360",
143+
"ap-south-1": "763104351884",
144+
"ap-southeast-1": "763104351884",
145+
"ap-southeast-2": "763104351884",
146+
"ca-central-1": "763104351884",
147+
"cn-north-1": "727897471807",
148+
"cn-northwest-1": "727897471807",
149+
"eu-central-1": "763104351884",
150+
"eu-north-1": "763104351884",
151+
"eu-west-1": "763104351884",
152+
"eu-west-2": "763104351884",
153+
"eu-west-3": "763104351884",
154+
"eu-south-1": "692866216735",
155+
"me-south-1": "217643126080",
156+
"sa-east-1": "763104351884",
157+
"us-east-1": "763104351884",
158+
"us-east-2": "763104351884",
159+
"us-gov-west-1": "442386744353",
160+
"us-iso-east-1": "886529160074",
161+
"us-west-1": "763104351884",
162+
"us-west-2": "763104351884"
163+
},
164+
"repository": "autogluon-inference",
165+
"py_versions": ["py38"]
166+
},
167+
"0.4.0": {
168+
"registries": {
169+
"af-south-1": "626614931356",
170+
"ap-east-1": "871362719292",
171+
"ap-northeast-1": "763104351884",
172+
"ap-northeast-2": "763104351884",
173+
"ap-northeast-3": "364406365360",
174+
"ap-south-1": "763104351884",
175+
"ap-southeast-1": "763104351884",
176+
"ap-southeast-2": "763104351884",
177+
"ca-central-1": "763104351884",
178+
"cn-north-1": "727897471807",
179+
"cn-northwest-1": "727897471807",
180+
"eu-central-1": "763104351884",
181+
"eu-north-1": "763104351884",
182+
"eu-west-1": "763104351884",
183+
"eu-west-2": "763104351884",
184+
"eu-west-3": "763104351884",
185+
"eu-south-1": "692866216735",
186+
"me-south-1": "217643126080",
187+
"sa-east-1": "763104351884",
188+
"us-east-1": "763104351884",
189+
"us-east-2": "763104351884",
190+
"us-gov-west-1": "442386744353",
191+
"us-iso-east-1": "886529160074",
192+
"us-west-1": "763104351884",
193+
"us-west-2": "763104351884"
194+
},
195+
"repository": "autogluon-inference",
196+
"py_versions": ["py38"]
69197
}
70198
}
71199
}

src/sagemaker/local/entities.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
import sagemaker.local.data
2424
from sagemaker.local.image import _SageMakerContainer
25-
from sagemaker.local.utils import copy_directory_structure, move_to_destination
25+
from sagemaker.local.utils import copy_directory_structure, move_to_destination, get_docker_host
2626
from sagemaker.utils import DeferredError, get_config_value
2727

2828
logger = logging.getLogger(__name__)
@@ -295,7 +295,7 @@ def start(self, input_data, output_data, transform_resources, **kwargs):
295295
_wait_for_serving_container(serving_port)
296296

297297
# Get capabilities from Container if needed
298-
endpoint_url = "http://localhost:%s/execution-parameters" % serving_port
298+
endpoint_url = "http://%s:%d/execution-parameters" % (get_docker_host(), serving_port)
299299
response, code = _perform_request(endpoint_url)
300300
if code == 200:
301301
execution_parameters = json.loads(response.read())
@@ -607,7 +607,7 @@ def _wait_for_serving_container(serving_port):
607607
i = 0
608608
http = urllib3.PoolManager()
609609

610-
endpoint_url = "http://localhost:%s/ping" % serving_port
610+
endpoint_url = "http://%s:%d/ping" % (get_docker_host(), serving_port)
611611
while True:
612612
i += 5
613613
if i >= HEALTH_CHECK_TIMEOUT_LIMIT:

src/sagemaker/local/local_session.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from botocore.exceptions import ClientError
2222

2323
from sagemaker.local.image import _SageMakerContainer
24+
from sagemaker.local.utils import get_docker_host
2425
from sagemaker.local.entities import (
2526
_LocalEndpointConfig,
2627
_LocalEndpoint,
@@ -448,7 +449,7 @@ def invoke_endpoint(
448449
Returns:
449450
object: Inference for the given input.
450451
"""
451-
url = "http://localhost:%s/invocations" % self.serving_port
452+
url = "http://%s:%d/invocations" % (get_docker_host(), self.serving_port)
452453
headers = {}
453454

454455
if ContentType is not None:

src/sagemaker/local/utils.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import os
1717
import shutil
1818
import subprocess
19+
import json
1920

2021
from distutils.dir_util import copy_tree
2122
from six.moves.urllib.parse import urlparse
@@ -127,3 +128,27 @@ def get_child_process_ids(pid):
127128
return pids + get_child_process_ids(child_pid)
128129
else:
129130
return []
131+
132+
133+
def get_docker_host():
134+
"""Discover remote docker host address (if applicable) or use "localhost"
135+
136+
Use "docker context inspect" to read current docker host endpoint url,
137+
url must start with "tcp://"
138+
139+
Args:
140+
141+
Returns:
142+
docker_host (str): Docker host DNS or IP address
143+
"""
144+
cmd = "docker context inspect".split()
145+
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
146+
output, err = process.communicate()
147+
if err:
148+
return "localhost"
149+
docker_context_string = output.decode("utf-8")
150+
docker_context_host_url = json.loads(docker_context_string)[0]["Endpoints"]["docker"]["Host"]
151+
parsed_url = urlparse(docker_context_host_url)
152+
if parsed_url.hostname and parsed_url.scheme == "tcp":
153+
return parsed_url.hostname
154+
return "localhost"

tests/unit/sagemaker/image_uris/test_autogluon.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,18 @@
4242
"us-west-1": "763104351884",
4343
"us-west-2": "763104351884",
4444
}
45-
VERSIONS = ["0.3.1"]
45+
VERSIONS = ["0.3.1", "0.3.2", "0.4.0", "0.3", "0.4"]
4646

4747

4848
@pytest.mark.parametrize("version", VERSIONS)
4949
def test_valid_uris(version):
50+
py_version = "py37" if version == "0.3.1" else "py38"
5051
for region in ACCOUNTS.keys():
5152
uri = image_uris.retrieve(
5253
"autogluon",
5354
region=region,
5455
version=version,
55-
py_version="py37",
56+
py_version=py_version,
5657
image_scope="training",
5758
instance_type="ml.c4.xlarge",
5859
)
@@ -61,7 +62,7 @@ def test_valid_uris(version):
6162
"autogluon-training",
6263
version,
6364
ACCOUNTS[region],
64-
py_version="py37",
65+
py_version=py_version,
6566
region=region,
6667
)
6768
assert uri == expected

tests/unit/test_local_entities.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,28 @@ def test_local_transform_job_perform_batch_inference(
163163
assert len(output_files) == 2
164164
assert "file1.out" in output_files
165165
assert "file2.out" in output_files
166+
167+
168+
@patch("sagemaker.local.entities._SageMakerContainer", Mock())
169+
@patch("sagemaker.local.entities.get_docker_host")
170+
@patch("sagemaker.local.entities._perform_request")
171+
@patch("sagemaker.local.entities._LocalTransformJob._perform_batch_inference")
172+
def test_start_local_transform_job_from_remote_docker_host(
173+
m_perform_batch_inference, m_perform_request, m_get_docker_host, local_transform_job
174+
):
175+
input_data = {}
176+
output_data = {}
177+
transform_resources = {"InstanceType": "local"}
178+
m_get_docker_host.return_value = "some_host"
179+
perform_request_mock = Mock()
180+
m_perform_request.return_value = (perform_request_mock, 200)
181+
perform_request_mock.read.return_value = '{"BatchStrategy": "SingleRecord"}'
182+
local_transform_job.primary_container["ModelDataUrl"] = "file:///some/model"
183+
local_transform_job.start(input_data, output_data, transform_resources, Environment={})
184+
endpoints = [
185+
"http://%s:%d/ping" % ("some_host", 8080),
186+
"http://%s:%d/execution-parameters" % ("some_host", 8080),
187+
]
188+
calls = m_perform_request.call_args_list
189+
for call, endpoint in zip(calls, endpoints):
190+
assert call[0][0] == endpoint

tests/unit/test_local_session.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,3 +857,18 @@ def test_local_session_download_with_custom_s3_endpoint_url(sagemaker_session_cu
857857
Filename="{}/{}".format(DOWNLOAD_DATA_TESTS_FILES_DIR, "test.csv"),
858858
ExtraArgs=None,
859859
)
860+
861+
862+
@patch("sagemaker.local.local_session.get_docker_host")
863+
@patch("urllib3.PoolManager.request")
864+
def test_invoke_local_endpoint_with_remote_docker_host(
865+
m_request,
866+
m_get_docker_host,
867+
):
868+
m_get_docker_host.return_value = "some_host"
869+
Body = "Body".encode("utf-8")
870+
url = "http://%s:%d/invocations" % ("some_host", 8080)
871+
sagemaker.local.local_session.LocalSagemakerRuntimeClient().invoke_endpoint(
872+
Body, "local_endpoint"
873+
)
874+
m_request.assert_called_with("POST", url, body=Body, preload_content=False, headers={})

tests/unit/test_local_utils.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,27 @@ def test_get_child_process_ids(m_subprocess):
9292
m_subprocess.Popen.return_value = process_mock
9393
sagemaker.local.utils.get_child_process_ids("pid")
9494
m_subprocess.Popen.assert_called_with(cmd, stdout=m_subprocess.PIPE, stderr=m_subprocess.PIPE)
95+
96+
97+
@patch("sagemaker.local.utils.subprocess")
98+
def test_get_docker_host(m_subprocess):
99+
cmd = "docker context inspect".split()
100+
process_mock = Mock()
101+
endpoints = [
102+
{"test": "tcp://host:port", "result": "host"},
103+
{"test": "fd://something", "result": "localhost"},
104+
{"test": "unix://path/to/socket", "result": "localhost"},
105+
{"test": "npipe:////./pipe/foo", "result": "localhost"},
106+
]
107+
for endpoint in endpoints:
108+
return_value = (
109+
'[\n{\n"Endpoints":{\n"docker":{\n"Host": "%s"}\n}\n}\n]\n' % endpoint["test"]
110+
)
111+
attrs = {"communicate.return_value": (return_value.encode("utf-8"), None), "returncode": 0}
112+
process_mock.configure_mock(**attrs)
113+
m_subprocess.Popen.return_value = process_mock
114+
host = sagemaker.local.utils.get_docker_host()
115+
m_subprocess.Popen.assert_called_with(
116+
cmd, stdout=m_subprocess.PIPE, stderr=m_subprocess.PIPE
117+
)
118+
assert host == endpoint["result"]

0 commit comments

Comments
 (0)