Skip to content

Commit d6ca6c1

Browse files
Rohan GujarathiNamrata Madan
authored andcommitted
Pathways: update input channel names and create sylinks for sagemaker whl file
1 parent 8c82136 commit d6ca6c1

File tree

5 files changed

+53
-28
lines changed

5 files changed

+53
-28
lines changed

src/sagemaker/remote_function/job.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
RUNTIME_MANAGER_SCRIPT_NAME = "runtime_environment_manager.py"
3838

3939
# training channel names
40-
RUNTIME_SCRIPTS_CHANNEL_NAME = "remote_function_scripts"
41-
USER_DEPENDENCIES_CHANNEL_NAME = "remote_function_dependencies"
40+
RUNTIME_SCRIPTS_CHANNEL_NAME = "sm_rf_bootstrap"
41+
REMOTE_FUNCTION_WORKSPACE = "sm_rf_user_ws"
4242
SAGEMAKER_WHL_CHANNEL_NAME = "sagemaker_whl_file"
4343

4444
SAGEMAKER_SDK_WHL_FILE = (
@@ -50,15 +50,15 @@
5050
f"/opt/ml/input/data/{RUNTIME_SCRIPTS_CHANNEL_NAME}/{ENTRYPOINT_SCRIPT_NAME}",
5151
]
5252

53-
ENTRYPOINT_SCRIPT = r"""
53+
ENTRYPOINT_SCRIPT = f"""
5454
#!/bin/bash
5555
5656
# Entry point for bootstrapping runtime environment and invoking remote function
5757
5858
set -eu
5959
60-
printf "INFO: Bootstraping runtime environment.\n"
61-
python /opt/ml/input/data/remote_function_scripts/bootstrap_runtime_environment.py "$@"
60+
printf "INFO: Bootstraping runtime environment.\\n"
61+
python /opt/ml/input/data/{RUNTIME_SCRIPTS_CHANNEL_NAME}/{BOOTSTRAP_SCRIPT_NAME} "$@"
6262
6363
if [ -f "remote_function_conda_env.txt" ]
6464
then
@@ -70,10 +70,10 @@
7070
conda_exe="conda"
7171
fi
7272
73-
printf "INFO: Invoking remote function inside conda environment: $conda_env.\n"
73+
printf "INFO: Invoking remote function inside conda environment: $conda_env.\\n"
7474
$conda_exe run -n $conda_env python -m sagemaker.remote_function.invoke_function "$@"
7575
else
76-
printf "INFO: No conda env provided. Invoking remote function\n"
76+
printf "INFO: No conda env provided. Invoking remote function\\n"
7777
python -m sagemaker.remote_function.invoke_function "$@"
7878
fi
7979
"""
@@ -222,7 +222,7 @@ def start(job_settings: _JobSettings, func, func_args, func_kwargs):
222222

223223
local_dependencies_path = RuntimeEnvironmentManager().snapshot(job_settings.dependencies)
224224

225-
remote_function_scripts_s3uri = _prepare_and_upload_runtime_scripts(
225+
bootstrap_scripts_s3uri = _prepare_and_upload_runtime_scripts(
226226
s3_base_uri=s3_base_uri,
227227
s3_kms_key=job_settings.s3_kms_key,
228228
sagemaker_session=job_settings.sagemaker_session,
@@ -258,7 +258,7 @@ def start(job_settings: _JobSettings, func, func_args, func_kwargs):
258258
ChannelName=RUNTIME_SCRIPTS_CHANNEL_NAME,
259259
DataSource={
260260
"S3DataSource": {
261-
"S3Uri": remote_function_scripts_s3uri,
261+
"S3Uri": bootstrap_scripts_s3uri,
262262
"S3DataType": "S3Prefix",
263263
}
264264
},
@@ -268,7 +268,7 @@ def start(job_settings: _JobSettings, func, func_args, func_kwargs):
268268
if user_dependencies_s3uri:
269269
input_data_config.append(
270270
dict(
271-
ChannelName=USER_DEPENDENCIES_CHANNEL_NAME,
271+
ChannelName=REMOTE_FUNCTION_WORKSPACE,
272272
DataSource={
273273
"S3DataSource": {
274274
"S3Uri": user_dependencies_s3uri,
@@ -383,10 +383,10 @@ def _prepare_and_upload_runtime_scripts(
383383
):
384384
"""Copy runtime scripts to a folder and upload to S3"""
385385

386-
with _tmpdir() as remote_function_scripts:
386+
with _tmpdir() as bootstrap_scripts:
387387

388388
# write entrypoint script to tmpdir
389-
entrypoint_script_path = os.path.join(remote_function_scripts, ENTRYPOINT_SCRIPT_NAME)
389+
entrypoint_script_path = os.path.join(bootstrap_scripts, ENTRYPOINT_SCRIPT_NAME)
390390
with open(entrypoint_script_path, "w") as file:
391391
file.writelines(ENTRYPOINT_SCRIPT)
392392

@@ -398,11 +398,11 @@ def _prepare_and_upload_runtime_scripts(
398398
)
399399

400400
# copy runtime scripts to tmpdir
401-
shutil.copy2(bootstrap_script_path, remote_function_scripts)
402-
shutil.copy2(runtime_manager_script_path, remote_function_scripts)
401+
shutil.copy2(bootstrap_script_path, bootstrap_scripts)
402+
shutil.copy2(runtime_manager_script_path, bootstrap_scripts)
403403

404404
return S3Uploader.upload(
405-
remote_function_scripts,
405+
bootstrap_scripts,
406406
s3_path_join(s3_base_uri, RUNTIME_SCRIPTS_CHANNEL_NAME),
407407
s3_kms_key,
408408
sagemaker_session,
@@ -416,7 +416,7 @@ def _prepare_and_upload_dependencies(
416416
if local_dependencies_path:
417417
return S3Uploader.upload(
418418
local_dependencies_path,
419-
s3_path_join(s3_base_uri, USER_DEPENDENCIES_CHANNEL_NAME),
419+
s3_path_join(s3_base_uri, REMOTE_FUNCTION_WORKSPACE),
420420
s3_kms_key,
421421
sagemaker_session,
422422
)

src/sagemaker/remote_function/runtime_environment/bootstrap_runtime_environment.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828
SUCCESS_EXIT_CODE = 0
2929
DEFAULT_FAILURE_CODE = 1
3030

31-
DEPENDENCY_FILE_CHANNEL_NAME = "remote_function_dependencies"
31+
REMOTE_FUNCTION_WORKSPACE = "sm_rf_user_ws"
3232
BASE_CHANNEL_PATH = "/opt/ml/input/data"
3333
FAILURE_REASON_PATH = "/opt/ml/output/failure"
34+
SAGEMAKER_WHL_FILE_NAME = "sagemaker-2.120.1.dev0-py2.py3-none-any.whl"
35+
SAGEMAKER_WHL_CHANNEL = "sagemaker_whl_file"
3436

3537

3638
logging.basicConfig(
@@ -73,7 +75,7 @@ def _bootstrap_runtime_environment(
7375
Args:
7476
job_conda_env (str): conda environment to be activated. Default is None.
7577
"""
76-
dependency_file_path = os.path.join(BASE_CHANNEL_PATH, DEPENDENCY_FILE_CHANNEL_NAME)
78+
dependency_file_path = os.path.join(BASE_CHANNEL_PATH, REMOTE_FUNCTION_WORKSPACE)
7779
dependency_file = None
7880

7981
if not os.path.exists(dependency_file_path):
@@ -86,13 +88,30 @@ def _bootstrap_runtime_environment(
8688
break
8789

8890
if dependency_file:
91+
_create_sm_installer_symlinks()
8992
RuntimeEnvironmentManager().bootstrap(
9093
local_dependencies_file=dependency_file, job_conda_env=job_conda_env
9194
)
9295
else:
9396
logger.info("No dependency file found")
9497

9598

99+
def _create_sm_installer_symlinks():
100+
"""Creates a symlink for sagemaker installer
101+
102+
This function create a symlink of sagemaker whl such that public beta users won't need
103+
to provide whl file path in their dependencies file. This logic should be removed before GA
104+
"""
105+
106+
whl_file_path = os.path.join(BASE_CHANNEL_PATH, SAGEMAKER_WHL_CHANNEL, SAGEMAKER_WHL_FILE_NAME)
107+
destination_path1 = os.path.join(
108+
BASE_CHANNEL_PATH, REMOTE_FUNCTION_WORKSPACE, SAGEMAKER_WHL_FILE_NAME
109+
)
110+
destination_path2 = os.path.join(os.getcwd(), SAGEMAKER_WHL_FILE_NAME)
111+
os.symlink(whl_file_path, destination_path1)
112+
os.symlink(whl_file_path, destination_path2)
113+
114+
96115
def _write_failure_reason_file(failure_msg):
97116
"""Create a file 'failure' with failure reason written if bootstrap runtime env failed.
98117

tests/integ/sagemaker/remote_function/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"dependencies:\n"
7171
" - scipy=1.10.0\n"
7272
" - pip:\n"
73-
" - /opt/ml/input/data/sagemaker_whl_file/sagemaker-2.120.1.dev0-py2.py3-none-any.whl[remote_function]\n"
73+
" - sagemaker-2.120.1.dev0-py2.py3-none-any.whl[remote_function]\n"
7474
"prefix: /opt/conda/bin/conda\n"
7575
)
7676

tests/unit/sagemaker/remote_function/runtime_environment/test_bootstrap_runtime_environment.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import sagemaker.remote_function.runtime_environment.bootstrap_runtime_environment as bootstrap
2121

2222
TEST_JOB_CONDA_ENV = "conda_env"
23-
TEST_DEPENDENCIES_PATH = "/opt/ml/input/data/remote_function_dependencies"
23+
TEST_DEPENDENCIES_PATH = "/opt/ml/input/data/sm_rf_user_ws"
2424

2525

2626
def mock_args():
@@ -33,13 +33,16 @@ def mock_args():
3333
"sagemaker.remote_function.runtime_environment.bootstrap_runtime_environment._parse_agrs",
3434
new=mock_args,
3535
)
36+
@patch(
37+
"sagemaker.remote_function.runtime_environment.bootstrap_runtime_environment._create_sm_installer_symlinks"
38+
)
3639
@patch("sys.exit")
3740
@patch("os.path.exists", return_value=True)
3841
@patch("os.listdir", return_value=["fileA.py", "fileB.sh", "requirements.txt"])
3942
@patch(
4043
"sagemaker.remote_function.runtime_environment.runtime_environment_manager.RuntimeEnvironmentManager.bootstrap"
4144
)
42-
def test_main_success(bootstrap_runtime, list_dir, path_exists, _exit_process):
45+
def test_main_success(bootstrap_runtime, list_dir, path_exists, _exit_process, symlink):
4346
bootstrap.main()
4447
path_exists.assert_called_once_with(TEST_DEPENDENCIES_PATH)
4548
list_dir.assert_called_once_with(TEST_DEPENDENCIES_PATH)
@@ -51,14 +54,17 @@ def test_main_success(bootstrap_runtime, list_dir, path_exists, _exit_process):
5154
"sagemaker.remote_function.runtime_environment.bootstrap_runtime_environment._parse_agrs",
5255
new=mock_args,
5356
)
57+
@patch(
58+
"sagemaker.remote_function.runtime_environment.bootstrap_runtime_environment._create_sm_installer_symlinks"
59+
)
5460
@patch("sys.exit")
5561
@patch(
5662
"sagemaker.remote_function.runtime_environment.bootstrap_runtime_environment._write_failure_reason_file"
5763
)
5864
@patch(
5965
"sagemaker.remote_function.runtime_environment.bootstrap_runtime_environment._bootstrap_runtime_environment"
6066
)
61-
def test_main_failure(bootstrap_runtime, write_failure, _exit_process):
67+
def test_main_failure(bootstrap_runtime, write_failure, _exit_process, symlink):
6268
runtime_err = RuntimeEnvironmentError("some failure reason")
6369
bootstrap_runtime.side_effect = runtime_err
6470

tests/unit/sagemaker/remote_function/test_job.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
DEFAULT_ROLE_ARN = "default_execution_role_arn"
3535
PATH_TO_SRC_DIR = "/path/to/source_dir"
3636
TEST_REGION = "us-west-2"
37-
RUNTIME_SCRIPTS_CHANNEL_NAME = "remote_function_scripts"
38-
USER_DEPENDENCIES_CHANNEL_NAME = "remote_function_dependencies"
37+
RUNTIME_SCRIPTS_CHANNEL_NAME = "sm_rf_bootstrap"
38+
REMOTE_FUNCTION_WORKSPACE = "sm_rf_user_ws"
3939
SAGEMAKER_WHL_CHANNEL_NAME = "sagemaker_whl_file"
4040
SAGEMAKER_SDK_WHL_FILE = (
4141
"s3://sagemaker-pathways/test/pysdk/sagemaker-2.120.1.dev0-py2.py3-none-any.whl"
@@ -187,7 +187,7 @@ def test_start(
187187
},
188188
),
189189
dict(
190-
ChannelName=USER_DEPENDENCIES_CHANNEL_NAME,
190+
ChannelName=REMOTE_FUNCTION_WORKSPACE,
191191
DataSource={
192192
"S3DataSource": {
193193
"S3Uri": mock_dependency_upload.return_value,
@@ -211,7 +211,7 @@ def test_start(
211211
TrainingInputMode="File",
212212
ContainerEntrypoint=[
213213
"/bin/bash",
214-
"/opt/ml/input/data/remote_function_scripts/job_driver.sh",
214+
"/opt/ml/input/data/sm_rf_bootstrap/job_driver.sh",
215215
],
216216
ContainerArguments=[
217217
"--s3_base_uri",
@@ -297,7 +297,7 @@ def test_start_with_complete_job_settings(
297297
},
298298
),
299299
dict(
300-
ChannelName=USER_DEPENDENCIES_CHANNEL_NAME,
300+
ChannelName=REMOTE_FUNCTION_WORKSPACE,
301301
DataSource={
302302
"S3DataSource": {
303303
"S3Uri": mock_dependency_upload.return_value,
@@ -321,7 +321,7 @@ def test_start_with_complete_job_settings(
321321
TrainingInputMode="File",
322322
ContainerEntrypoint=[
323323
"/bin/bash",
324-
"/opt/ml/input/data/remote_function_scripts/job_driver.sh",
324+
"/opt/ml/input/data/sm_rf_bootstrap/job_driver.sh",
325325
],
326326
ContainerArguments=[
327327
"--s3_base_uri",

0 commit comments

Comments
 (0)