diff --git a/mlrun/api/api/utils.py b/mlrun/api/api/utils.py index 69651b7589e..42a77ce5923 100644 --- a/mlrun/api/api/utils.py +++ b/mlrun/api/api/utils.py @@ -33,16 +33,27 @@ def log_path(project, uid) -> Path: def get_obj_path(schema, path, user=""): - if schema: - return schema + "://" + path - elif path.startswith("/User/"): + if path.startswith("/User/"): user = user or environ.get("V3IO_USERNAME", "admin") - return "v3io:///users/" + user + path[5:] + path = "v3io:///users/" + user + path[5:] + schema = schema or "v3io" + elif path.startswith("/v3io"): + path = "v3io://" + path[len("/v3io") :] + schema = schema or "v3io" elif config.httpdb.data_volume and path.startswith(config.httpdb.data_volume): + data_volume_prefix = config.httpdb.data_volume + if data_volume_prefix.endswith("/"): + data_volume_prefix = data_volume_prefix[:-1] if config.httpdb.real_path: - path = config.httpdb.real_path + path[len(config.httpdb.data_volume) - 1 :] - return path - return None + path_from_volume = path[len(data_volume_prefix) :] + if path_from_volume.startswith("/"): + path_from_volume = path_from_volume[1:] + path = str(Path(config.httpdb.real_path) / Path(path_from_volume)) + if schema: + schema_prefix = schema + "://" + if not path.startswith(schema_prefix): + return schema + "://" + path + return path def get_secrets(_request: Request): diff --git a/tests/api/api/test_utils.py b/tests/api/api/test_utils.py index 11188dae796..cd1a892e2f0 100644 --- a/tests/api/api/test_utils.py +++ b/tests/api/api/test_utils.py @@ -1,9 +1,10 @@ from http import HTTPStatus +from deepdiff import DeepDiff from fastapi.testclient import TestClient from sqlalchemy.orm import Session -from deepdiff import DeepDiff +import mlrun from mlrun.api.api.utils import _parse_submit_run_body @@ -126,6 +127,81 @@ def test_parse_submit_job_body_keep_resources(db: Session, client: TestClient): ) +def test_get_obj_path(db: Session, client: TestClient): + cases = [ + {"path": "/local/path", "expected_path": "/local/path"}, + { + "path": "/local/path", + "schema": "v3io", + "expected_path": "v3io:///local/path", + }, + {"path": "/User/my/path", "expected_path": "v3io:///users/admin/my/path"}, + { + "path": "/User/my/path", + "schema": "v3io", + "expected_path": "v3io:///users/admin/my/path", + }, + { + "path": "/User/my/path", + "user": "hedi", + "expected_path": "v3io:///users/hedi/my/path", + }, + { + "path": "/v3io/projects/my-proj/my/path", + "expected_path": "v3io:///projects/my-proj/my/path", + }, + { + "path": "/v3io/projects/my-proj/my/path", + "schema": "v3io", + "expected_path": "v3io:///projects/my-proj/my/path", + }, + { + "path": "/home/jovyan/data/my/path", + "data_volume": "/home/jovyan/data", + "expected_path": "/home/jovyan/data/my/path", + }, + { + "path": "/home/jovyan/data/my/path", + "data_volume": "/home/jovyan/data", + "real_path": "/root", + "expected_path": "/root/my/path", + }, + { + "path": "/home/jovyan/data/my/path", + "data_volume": "/home/jovyan/data/", + "real_path": "/root", + "expected_path": "/root/my/path", + }, + { + "path": "/home/jovyan/data/my/path", + "data_volume": "/home/jovyan/data/", + "real_path": "/root/", + "expected_path": "/root/my/path", + }, + { + "path": "/home/jovyan/data/my/path", + "data_volume": "/home/jovyan/data", + "real_path": "/root", + "expected_path": "/root/my/path", + }, + ] + for case in cases: + old_real_path = mlrun.mlconf.httpdb.real_path + old_data_volume = mlrun.mlconf.httpdb.data_volume + if case.get("real_path"): + mlrun.mlconf.httpdb.real_path = case["real_path"] + if case.get("data_volume"): + mlrun.mlconf.httpdb.data_volume = case["data_volume"] + result_path = mlrun.api.api.utils.get_obj_path( + case.get("schema"), case.get("path"), case.get("user") + ) + assert result_path == case["expected_path"] + if case.get("real_path"): + mlrun.mlconf.httpdb.real_path = old_real_path + if case.get("data_volume"): + mlrun.mlconf.httpdb.data_volume = old_data_volume + + def _mock_original_function(client): function_name = "function_name" project = "some-project"