Skip to content

Commit 680cb67

Browse files
rohangujarathiRohan Gujarathi
authored andcommitted
fix: use copy instead of move in bootstrap script (#1339)
Co-authored-by: Rohan Gujarathi <[email protected]>
1 parent 8f2adec commit 680cb67

File tree

5 files changed

+95
-7
lines changed

5 files changed

+95
-7
lines changed

src/sagemaker/remote_function/runtime_environment/bootstrap_runtime_environment.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def _bootstrap_runtime_env_for_pipeline_step(
140140
for file in os.listdir(pre_exec_script_and_dependencies_dir):
141141
src_path = os.path.join(pre_exec_script_and_dependencies_dir, file)
142142
dest_path = os.path.join(workspace_dir, file)
143-
shutil.move(src_path, dest_path)
143+
shutil.copy(src_path, dest_path)
144144

145145
_handle_pre_exec_scripts(workspace_dir)
146146

tests/integ/sagemaker/conftest.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,21 @@
6161
"ENV SAGEMAKER_JOB_CONDA_ENV=default_env\n"
6262
)
6363

64+
DOCKERFILE_TEMPLATE_WITH_USER_AND_WORKDIR = (
65+
"FROM public.ecr.aws/docker/library/python:{py_version}-slim\n\n"
66+
"RUN apt-get update -y \
67+
&& apt-get install -y unzip curl\n\n"
68+
"RUN curl 'https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip' -o 'awscliv2.zip' \
69+
&& unzip awscliv2.zip \
70+
&& ./aws/install\n\n"
71+
"RUN useradd -ms /bin/bash integ-test-user\n"
72+
"USER integ-test-user\n"
73+
"WORKDIR /home/integ-test-user\n"
74+
"COPY {source_archive} ./\n"
75+
"RUN pip install '{source_archive}'\n"
76+
"RUN rm {source_archive}\n"
77+
)
78+
6479
AUTO_CAPTURE_CLIENT_DOCKER_TEMPLATE = (
6580
"FROM public.ecr.aws/docker/library/python:{py_version}-slim\n\n"
6681
'SHELL ["/bin/bash", "-c"]\n'
@@ -105,6 +120,14 @@ def dummy_container_without_error(sagemaker_session, compatible_python_version):
105120
return ecr_uri
106121

107122

123+
@pytest.fixture(scope="session")
124+
def dummy_container_with_user_and_workdir(sagemaker_session, compatible_python_version):
125+
ecr_uri = _build_container(
126+
sagemaker_session, compatible_python_version, DOCKERFILE_TEMPLATE_WITH_USER_AND_WORKDIR
127+
)
128+
return ecr_uri
129+
130+
108131
@pytest.fixture(scope="session")
109132
def dummy_container_incompatible_python_runtime(sagemaker_session, incompatible_python_version):
110133
ecr_uri = _build_container(sagemaker_session, incompatible_python_version, DOCKERFILE_TEMPLATE)

tests/integ/sagemaker/remote_function/test_decorator.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,26 @@ def load_checkpoints(checkpoint_path: Union[str, os.PathLike]):
727727
)
728728

729729

730+
def test_with_user_and_workdir_set_in_the_image(
731+
sagemaker_session, dummy_container_with_user_and_workdir, cpu_instance_type
732+
):
733+
dependencies_path = os.path.join(DATA_DIR, "remote_function", "requirements.txt")
734+
735+
@remote(
736+
role=ROLE,
737+
image_uri=dummy_container_with_user_and_workdir,
738+
dependencies=dependencies_path,
739+
instance_type=cpu_instance_type,
740+
sagemaker_session=sagemaker_session,
741+
)
742+
def cuberoot(x):
743+
from scipy.special import cbrt
744+
745+
return cbrt(27)
746+
747+
assert cuberoot(27) == 3
748+
749+
730750
@pytest.mark.skip
731751
def test_decorator_with_spark_job(sagemaker_session, cpu_instance_type):
732752
@remote(

tests/integ/sagemaker/workflow/test_step_decorator.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,3 +813,48 @@ def updated_func(x):
813813
pipeline.delete()
814814
except Exception:
815815
pass
816+
817+
818+
def test_with_user_and_workdir_set_in_the_image(
819+
sagemaker_session, role, pipeline_name, region_name, dummy_container_with_user_and_workdir
820+
):
821+
os.environ["AWS_DEFAULT_REGION"] = region_name
822+
dependencies_path = os.path.join(DATA_DIR, "workflow", "requirements.txt")
823+
824+
@step(
825+
role=role,
826+
image_uri=dummy_container_with_user_and_workdir,
827+
dependencies=dependencies_path,
828+
instance_type=INSTANCE_TYPE,
829+
)
830+
def cuberoot(x):
831+
from scipy.special import cbrt
832+
833+
return cbrt(x)
834+
835+
step_a = cuberoot(8)
836+
837+
pipeline = Pipeline(
838+
name=pipeline_name,
839+
steps=[step_a],
840+
sagemaker_session=sagemaker_session,
841+
)
842+
843+
try:
844+
create_and_execute_pipeline(
845+
pipeline=pipeline,
846+
pipeline_name=pipeline_name,
847+
region_name=region_name,
848+
role=role,
849+
no_of_steps=1,
850+
last_step_name="cuberoot",
851+
execution_parameters=dict(),
852+
step_status="Succeeded",
853+
step_result_type=numpy.float64,
854+
step_result_value=2.0,
855+
)
856+
finally:
857+
try:
858+
pipeline.delete()
859+
except Exception:
860+
pass

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ def test_bootstrap_runtime_env_for_remote_no_workspace(
370370
install_dependencies.assert_not_called()
371371

372372

373-
@patch("shutil.move")
373+
@patch("shutil.copy")
374374
@patch("os.listdir", return_value=[PRE_EXECUTION_SCRIPT_NAME, TEST_DEPENDENCY_FILE_NAME])
375375
@patch("os.path.exists", return_value=True)
376376
@patch(
@@ -384,7 +384,7 @@ def test_bootstrap_runtime_env_for_remote_no_workspace(
384384
return_value=pathlib.Path(TEST_DEPENDENCIES_PATH),
385385
)
386386
def test_bootstrap_runtime_env_for_step(
387-
unpack_workspace, install_scripts, install_dependencies, path_exists, list_dir, move_files
387+
unpack_workspace, install_scripts, install_dependencies, path_exists, list_dir, copy_files
388388
):
389389
bootstrap._bootstrap_runtime_env_for_pipeline_step(
390390
TEST_PYTHON_VERSION,
@@ -397,7 +397,7 @@ def test_bootstrap_runtime_env_for_step(
397397
dependency_dir = TEST_BASE_CHANNEL_PATH + PIPELINE_STEP_CHANNEL
398398
path_exists.assert_called_once_with(dependency_dir)
399399
list_dir.assert_called_once_with(dependency_dir)
400-
assert move_files.call_count == 2
400+
assert copy_files.call_count == 2
401401
install_scripts.assert_called_once_with(unpack_workspace.return_value)
402402
install_dependencies.assert_called_once_with(
403403
unpack_workspace.return_value,
@@ -410,7 +410,7 @@ def test_bootstrap_runtime_env_for_step(
410410

411411
@patch("os.getcwd", return_value=CURR_WORKING_DIR)
412412
@patch("os.mkdir")
413-
@patch("shutil.move")
413+
@patch("shutil.copy")
414414
@patch("os.listdir", return_value=[PRE_EXECUTION_SCRIPT_NAME, TEST_DEPENDENCY_FILE_NAME])
415415
@patch("os.path.exists", return_value=True)
416416
@patch(
@@ -429,7 +429,7 @@ def test_bootstrap_runtime_env_for_step_no_workspace(
429429
install_dependencies,
430430
path_exists,
431431
list_dir,
432-
move_files,
432+
copy_files,
433433
mkdir,
434434
get_cwd,
435435
):
@@ -447,7 +447,7 @@ def test_bootstrap_runtime_env_for_step_no_workspace(
447447
dependency_dir = TEST_BASE_CHANNEL_PATH + PIPELINE_STEP_CHANNEL
448448
path_exists.assert_called_once_with(dependency_dir)
449449
list_dir.assert_called_once_with(dependency_dir)
450-
assert move_files.call_count == 2
450+
assert copy_files.call_count == 2
451451
install_scripts.assert_called_once_with(pathlib.Path(TEST_DEPENDENCIES_PATH))
452452
install_dependencies.assert_called_once_with(
453453
pathlib.Path(TEST_DEPENDENCIES_PATH),

0 commit comments

Comments
 (0)