Skip to content

Commit fc8cca9

Browse files
committed
Added support for customizing destination path for job mount file system.
1 parent b835edb commit fc8cca9

File tree

3 files changed

+74
-30
lines changed

3 files changed

+74
-30
lines changed

ads/common/dsc_file_system.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class DSCFileSystem:
2020
dest: str = None
2121
storage_type: str = None
2222
destination_directory_name: str = None
23+
destination_path: str = None
2324

2425
def update_to_dsc_model(self) -> dict:
2526
"""Updates arguments to dsc model.
@@ -47,6 +48,25 @@ def update_from_dsc_model(cls, dsc_model) -> dict:
4748
"""
4849
pass
4950

51+
@staticmethod
52+
def get_destination_path_and_name(dest: str) -> (str, str):
53+
"""Gets the destination path and destination directory name from dest.
54+
55+
Parameters
56+
----------
57+
dest: str
58+
The dest path to which to mount the file system.
59+
60+
Returns
61+
-------
62+
tuple
63+
A tuple of destination path and destination directory name.
64+
"""
65+
directory_index = dest.rfind("/")
66+
directory_name = dest[directory_index+1:]
67+
path = "/" if directory_index <= 0 else dest[:directory_index]
68+
return (path, directory_name)
69+
5070

5171
@dataclass
5272
class OCIFileStorage(DSCFileSystem):
@@ -65,8 +85,10 @@ def update_to_dsc_model(self) -> dict:
6585
dict:
6686
A dictionary of arguments.
6787
"""
88+
path, directory_name = self.get_destination_path_and_name(self.dest)
6889
arguments = {
69-
"destinationDirectoryName" : self.dest,
90+
"destinationDirectoryName" : directory_name,
91+
"destinationPath" : path,
7092
"storageType" : self.storage_type
7193
}
7294

@@ -177,10 +199,14 @@ def update_from_dsc_model(cls, dsc_model) -> dict:
177199
raise ValueError(
178200
"Missing parameter `destination_directory_name` from service. Check service log to see the error."
179201
)
202+
if not dsc_model.destination_path:
203+
raise ValueError(
204+
"Missing parameter `destination_path` from service. Check service log to see the error."
205+
)
180206

181207
return {
182208
"src" : f"{dsc_model.mount_target_id}:{dsc_model.export_id}",
183-
"dest" : dsc_model.destination_directory_name
209+
"dest" : f"{dsc_model.destination_path.rstrip('/')}/{dsc_model.destination_directory_name}"
184210
}
185211

186212
@dataclass
@@ -189,8 +215,10 @@ class OCIObjectStorage(DSCFileSystem):
189215
storage_type: str = OBJECT_STORAGE_TYPE
190216

191217
def update_to_dsc_model(self) -> dict:
218+
path, directory_name = self.get_destination_path_and_name(self.dest)
192219
arguments = {
193-
"destinationDirectoryName" : self.dest,
220+
"destinationDirectoryName" : directory_name,
221+
"destinationPath" : path,
194222
"storageType" : self.storage_type
195223
}
196224
src_list = self.src.split("@")
@@ -219,10 +247,14 @@ def update_from_dsc_model(cls, dsc_model) -> dict:
219247
raise ValueError(
220248
"Missing parameter `destination_directory_name` from service. Check service log to see the error."
221249
)
250+
if not dsc_model.destination_path:
251+
raise ValueError(
252+
"Missing parameter `destination_path` from service. Check service log to see the error."
253+
)
222254

223255
return {
224256
"src" : f"oci://{dsc_model.bucket}@{dsc_model.namespace}/{dsc_model.prefix or ''}",
225-
"dest" : dsc_model.destination_directory_name
257+
"dest" : f"{dsc_model.destination_path.rstrip('/')}/{dsc_model.destination_directory_name}"
226258
}
227259

228260

ads/jobs/builders/infrastructure/dsc_job.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1482,7 +1482,7 @@ def _update_job_infra(self, dsc_job: DSCJob) -> DataScienceJob:
14821482

14831483
if self.storage_mount:
14841484
if not hasattr(
1485-
oci.data_science.models, "JobStorageMountConfigurationDetails"
1485+
oci.data_science.models, "StorageMountConfigurationDetails"
14861486
):
14871487
raise EnvironmentError(
14881488
"Storage mount hasn't been supported in the current OCI SDK installed."

tests/unitary/default_setup/jobs/test_jobs_mount_file_system.py

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from ads.jobs.builders.runtimes.python_runtime import PythonRuntime
1616

1717
try:
18-
from oci.data_science.models import JobStorageMountConfigurationDetails
1918
from oci.data_science.models import FileStorageMountConfigurationDetails
2019
from oci.data_science.models import ObjectStorageMountConfigurationDetails
2120
except (ImportError, AttributeError) as e:
@@ -50,6 +49,7 @@
5049
FileStorageMountConfigurationDetails(
5150
**{
5251
"destination_directory_name": "test_destination_directory_name_from_dsc",
52+
"destination_path": "/test_destination_path",
5353
"export_id": "export_id_from_dsc",
5454
"mount_target_id": "mount_target_id_from_dsc",
5555
"storage_type": "FILE_STORAGE",
@@ -58,6 +58,7 @@
5858
FileStorageMountConfigurationDetails(
5959
**{
6060
"destination_directory_name": "test_destination_directory_name_from_dsc",
61+
"destination_path": "/test_destination_path",
6162
"export_id": "export_id_from_dsc",
6263
"mount_target_id": "mount_target_id_from_dsc",
6364
"storage_type": "FILE_STORAGE",
@@ -80,15 +81,15 @@
8081
.with_storage_mount(
8182
{
8283
"src" : "1.1.1.1:test_export_path_one",
83-
"dest" : "test_mount_one",
84+
"dest" : "/test_path_one/test_mount_one",
8485
},
8586
{
8687
"src" : "2.2.2.2:test_export_path_two",
87-
"dest" : "test_mount_two",
88+
"dest" : "/test_path_two/test_mount_two",
8889
},
8990
{
9091
"src" : "oci://bucket_name@namespace/synthetic/",
91-
"dest" : "test_mount_three",
92+
"dest" : "/test_path_three/test_mount_three",
9293
}
9394
)
9495
)
@@ -114,11 +115,11 @@
114115
shapeName: VM.Standard.E3.Flex
115116
storageMount:
116117
- src: 1.1.1.1:test_export_path_one
117-
dest: test_mount_one
118+
dest: /test_path_one/test_mount_one
118119
- src: 2.2.2.2:test_export_path_two
119-
dest: test_mount_two
120+
dest: /test_path_two/test_mount_two
120121
- src: oci://bucket_name@namespace/synthetic/
121-
dest: test_mount_three
122+
dest: /test_path_three/test_mount_three
122123
subnetId: ocid1.subnet.oc1.iad.xxxx
123124
type: dataScienceJob
124125
name: My Job
@@ -142,17 +143,17 @@ def test_data_science_job_initialize(self):
142143
dsc_file_storage_one = job.infrastructure.storage_mount[0]
143144
assert isinstance(dsc_file_storage_one, dict)
144145
assert dsc_file_storage_one["src"] == "1.1.1.1:test_export_path_one"
145-
assert dsc_file_storage_one["dest"] == "test_mount_one"
146+
assert dsc_file_storage_one["dest"] == "/test_path_one/test_mount_one"
146147

147148
dsc_file_storage_two = job.infrastructure.storage_mount[1]
148149
assert isinstance(dsc_file_storage_two, dict)
149150
assert dsc_file_storage_two["src"] == "2.2.2.2:test_export_path_two"
150-
assert dsc_file_storage_two["dest"] == "test_mount_two"
151+
assert dsc_file_storage_two["dest"] == "/test_path_two/test_mount_two"
151152

152153
dsc_object_storage = job.infrastructure.storage_mount[2]
153154
assert isinstance(dsc_object_storage, dict)
154155
assert dsc_object_storage["src"] == "oci://bucket_name@namespace/synthetic/"
155-
assert dsc_object_storage["dest"] == "test_mount_three"
156+
assert dsc_object_storage["dest"] == "/test_path_three/test_mount_three"
156157

157158
def test_data_science_job_from_yaml(self):
158159
job_from_yaml = Job.from_yaml(job_yaml_string)
@@ -161,17 +162,17 @@ def test_data_science_job_from_yaml(self):
161162
dsc_file_storage_one = job_from_yaml.infrastructure.storage_mount[0]
162163
assert isinstance(dsc_file_storage_one, dict)
163164
assert dsc_file_storage_one["src"] == "1.1.1.1:test_export_path_one"
164-
assert dsc_file_storage_one["dest"] == "test_mount_one"
165+
assert dsc_file_storage_one["dest"] == "/test_path_one/test_mount_one"
165166

166167
dsc_file_storage_two = job.infrastructure.storage_mount[1]
167168
assert isinstance(dsc_file_storage_two, dict)
168169
assert dsc_file_storage_two["src"] == "2.2.2.2:test_export_path_two"
169-
assert dsc_file_storage_two["dest"] == "test_mount_two"
170+
assert dsc_file_storage_two["dest"] == "/test_path_two/test_mount_two"
170171

171172
dsc_object_storage = job.infrastructure.storage_mount[2]
172173
assert isinstance(dsc_object_storage, dict)
173174
assert dsc_object_storage["src"] == "oci://bucket_name@namespace/synthetic/"
174-
assert dsc_object_storage["dest"] == "test_mount_three"
175+
assert dsc_object_storage["dest"] == "/test_path_three/test_mount_three"
175176

176177
def test_data_science_job_to_dict(self):
177178
assert job.to_dict() == {
@@ -201,15 +202,15 @@ def test_data_science_job_to_dict(self):
201202
"storageMount": [
202203
{
203204
"src" : "1.1.1.1:test_export_path_one",
204-
"dest" : "test_mount_one",
205+
"dest" : "/test_path_one/test_mount_one",
205206
},
206207
{
207208
"src" : "2.2.2.2:test_export_path_two",
208-
"dest" : "test_mount_two",
209+
"dest" : "/test_path_two/test_mount_two",
209210
},
210211
{
211212
"src" : "oci://bucket_name@namespace/synthetic/",
212-
"dest" : "test_mount_three",
213+
"dest" : "/test_path_three/test_mount_three",
213214
}
214215
],
215216
},
@@ -260,11 +261,11 @@ def test_update_storage_mount_from_dsc_model(
260261
assert isinstance(infrastructure.storage_mount[1], dict)
261262
assert infrastructure.storage_mount[0] == {
262263
"src" : "mount_target_id_from_dsc:export_id_from_dsc",
263-
"dest" : "test_destination_directory_name_from_dsc"
264+
"dest" : "/test_destination_path/test_destination_directory_name_from_dsc"
264265
}
265266
assert infrastructure.storage_mount[1] == {
266267
"src" : "mount_target_id_from_dsc:export_id_from_dsc",
267-
"dest" : "test_destination_directory_name_from_dsc"
268+
"dest" : "/test_destination_path/test_destination_directory_name_from_dsc"
268269
}
269270

270271
@patch.object(OCIFileStorage, "update_to_dsc_model")
@@ -276,6 +277,7 @@ def test_update_job_infra(
276277

277278
mock_update_to_dsc_model.return_value = {
278279
"destinationDirectoryName": "test_destination_directory_name_from_dsc",
280+
"destination_path": "/test_destination_path",
279281
"exportId": "test_export_id_one",
280282
"mountTargetId": "test_mount_target_id_one",
281283
"storageType": "FILE_STORAGE",
@@ -293,6 +295,7 @@ def test_update_job_infra(
293295
0
294296
] == {
295297
"destinationDirectoryName": "test_destination_directory_name_from_dsc",
298+
"destination_path": "/test_destination_path",
296299
"exportId": "test_export_id_one",
297300
"mountTargetId": "test_mount_target_id_one",
298301
"storageType": "FILE_STORAGE",
@@ -358,7 +361,7 @@ def test_file_manager_process_data_error(self):
358361
def test_dsc_object_storage(self):
359362
object_storage = OCIObjectStorage(
360363
src="oci://bucket@namespace/prefix",
361-
dest="test_dest",
364+
dest="/test_path/test_dest",
362365
)
363366

364367
result = object_storage.update_to_dsc_model()
@@ -367,10 +370,12 @@ def test_dsc_object_storage(self):
367370
assert result["prefix"] == "prefix"
368371
assert result["storageType"] == "OBJECT_STORAGE"
369372
assert result["destinationDirectoryName"] == "test_dest"
373+
assert result["destinationPath"] == "/test_path"
370374

371375
dsc_model = ObjectStorageMountConfigurationDetails(
372376
**{
373377
"destination_directory_name": "test_destination_directory_name_from_dsc",
378+
"destination_path": "/test_destination_path",
374379
"storage_type": "OBJECT_STORAGE",
375380
"bucket": "bucket",
376381
"namespace": "namespace",
@@ -380,17 +385,19 @@ def test_dsc_object_storage(self):
380385

381386
result = OCIObjectStorage.update_from_dsc_model(dsc_model)
382387
assert result["src"] == "oci://bucket@namespace/prefix"
383-
assert result["dest"] == "test_destination_directory_name_from_dsc"
388+
assert result["dest"] == "/test_destination_path/test_destination_directory_name_from_dsc"
384389

385390
def test_dsc_object_storage_error(self):
386391
error_messages = {
387392
"namespace" : "Missing parameter `namespace` from service. Check service log to see the error.",
388393
"bucket" : "Missing parameter `bucket` from service. Check service log to see the error.",
389-
"destination_directory_name" : "Missing parameter `destination_directory_name` from service. Check service log to see the error."
394+
"destination_directory_name" : "Missing parameter `destination_directory_name` from service. Check service log to see the error.",
395+
"destination_path" : "Missing parameter `destination_path` from service. Check service log to see the error."
390396
}
391397

392398
dsc_model_dict = {
393399
"destination_directory_name": "test_destination_directory_name_from_dsc",
400+
"destination_path": "/test_path",
394401
"storage_type": "OBJECT_STORAGE",
395402
"bucket": "bucket",
396403
"namespace": "namespace",
@@ -412,19 +419,20 @@ def test_dsc_object_storage_error(self):
412419
def test_dsc_file_storage(self, mock_search_resources):
413420
file_storage = OCIFileStorage(
414421
src="ocid1.mounttarget.oc1.iad.xxxx:ocid1.export.oc1.iad.xxxx",
415-
dest="test_dest",
422+
dest="/test_path/test_dest",
416423
)
417424
file_storage = file_storage.update_to_dsc_model()
418425
assert file_storage == {
419426
"destinationDirectoryName" : "test_dest",
427+
"destinationPath" : "/test_path",
420428
"exportId" : "ocid1.export.oc1.iad.xxxx",
421429
"mountTargetId" : "ocid1.mounttarget.oc1.iad.xxxx",
422430
"storageType" : "FILE_STORAGE"
423431
}
424432

425433
file_storage = OCIFileStorage(
426434
src="1.1.1.1:/test_export",
427-
dest="test_dest",
435+
dest="/test_path/test_dest",
428436
)
429437

430438
items = [
@@ -477,6 +485,7 @@ def test_dsc_file_storage(self, mock_search_resources):
477485
file_storage = file_storage.update_to_dsc_model()
478486
assert file_storage == {
479487
"destinationDirectoryName" : "test_dest",
488+
"destinationPath" : "/test_path",
480489
"exportId" : "ocid1.export.oc1.iad.xxxx",
481490
"mountTargetId" : "ocid1.mounttarget.oc1.iad.xxxx",
482491
"storageType" : "FILE_STORAGE"
@@ -485,24 +494,27 @@ def test_dsc_file_storage(self, mock_search_resources):
485494
dsc_model = FileStorageMountConfigurationDetails(
486495
**{
487496
"destination_directory_name": "test_dest",
497+
"destination_path" : "/test_path",
488498
"storage_type": "FILE_STORAGE",
489499
"export_id": "ocid1.export.oc1.iad.xxxx",
490500
"mount_target_id": "ocid1.mounttarget.oc1.iad.xxxx"
491501
}
492502
)
493503
result = OCIFileStorage.update_from_dsc_model(dsc_model)
494504
assert result["src"] == "ocid1.mounttarget.oc1.iad.xxxx:ocid1.export.oc1.iad.xxxx"
495-
assert result["dest"] == "test_dest"
505+
assert result["dest"] == "/test_path/test_dest"
496506

497507
def test_dsc_file_storage_error(self):
498508
error_messages = {
499509
"mount_target_id" : "Missing parameter `mount_target_id` from service. Check service log to see the error.",
500510
"export_id" : "Missing parameter `export_id` from service. Check service log to see the error.",
501-
"destination_directory_name" : "Missing parameter `destination_directory_name` from service. Check service log to see the error."
511+
"destination_directory_name" : "Missing parameter `destination_directory_name` from service. Check service log to see the error.",
512+
"destination_path" : "Missing parameter `destination_path` from service. Check service log to see the error."
502513
}
503514

504515
dsc_model_dict = {
505516
"destination_directory_name": "test_destination_directory_name_from_dsc",
517+
"destination_path": "/test_path",
506518
"storage_type": "FILE_STORAGE",
507519
"mount_target_id": "ocid1.mounttarget.oc1.iad.xxxx",
508520
"export_id": "ocid1.export.oc1.iad.xxxx",

0 commit comments

Comments
 (0)