mlrun 1.6.1__py3-none-any.whl → 1.6.2rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mlrun might be problematic. Click here for more details.

Files changed (44) hide show
  1. mlrun/common/model_monitoring/helpers.py +4 -2
  2. mlrun/common/schemas/__init__.py +1 -0
  3. mlrun/common/schemas/common.py +40 -0
  4. mlrun/common/schemas/project.py +2 -0
  5. mlrun/config.py +13 -7
  6. mlrun/datastore/azure_blob.py +9 -9
  7. mlrun/datastore/google_cloud_storage.py +6 -6
  8. mlrun/db/base.py +18 -0
  9. mlrun/db/httpdb.py +28 -25
  10. mlrun/execution.py +3 -3
  11. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +3 -3
  12. mlrun/frameworks/tf_keras/model_handler.py +7 -7
  13. mlrun/k8s_utils.py +10 -5
  14. mlrun/kfpops.py +19 -10
  15. mlrun/model.py +5 -0
  16. mlrun/model_monitoring/api.py +8 -8
  17. mlrun/model_monitoring/batch.py +1 -1
  18. mlrun/model_monitoring/stores/kv_model_endpoint_store.py +13 -13
  19. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -1
  20. mlrun/package/packagers/pandas_packagers.py +3 -3
  21. mlrun/package/utils/_archiver.py +3 -1
  22. mlrun/platforms/iguazio.py +6 -65
  23. mlrun/projects/pipelines.py +21 -11
  24. mlrun/projects/project.py +65 -46
  25. mlrun/runtimes/base.py +20 -1
  26. mlrun/runtimes/function.py +9 -9
  27. mlrun/runtimes/kubejob.py +5 -3
  28. mlrun/runtimes/local.py +2 -2
  29. mlrun/runtimes/mpijob/abstract.py +6 -6
  30. mlrun/runtimes/pod.py +3 -3
  31. mlrun/runtimes/serving.py +3 -3
  32. mlrun/runtimes/sparkjob/spark3job.py +3 -3
  33. mlrun/serving/remote.py +4 -2
  34. mlrun/utils/async_http.py +3 -3
  35. mlrun/utils/helpers.py +8 -0
  36. mlrun/utils/http.py +3 -3
  37. mlrun/utils/notifications/notification_pusher.py +6 -6
  38. mlrun/utils/version/version.json +2 -2
  39. {mlrun-1.6.1.dist-info → mlrun-1.6.2rc1.dist-info}/METADATA +12 -14
  40. {mlrun-1.6.1.dist-info → mlrun-1.6.2rc1.dist-info}/RECORD +44 -43
  41. {mlrun-1.6.1.dist-info → mlrun-1.6.2rc1.dist-info}/LICENSE +0 -0
  42. {mlrun-1.6.1.dist-info → mlrun-1.6.2rc1.dist-info}/WHEEL +0 -0
  43. {mlrun-1.6.1.dist-info → mlrun-1.6.2rc1.dist-info}/entry_points.txt +0 -0
  44. {mlrun-1.6.1.dist-info → mlrun-1.6.2rc1.dist-info}/top_level.txt +0 -0
@@ -179,7 +179,9 @@ class _TarArchiver(_Archiver):
179
179
 
180
180
  # Extract:
181
181
  with tarfile.open(archive_path, f"r:{cls._MODE_STRING}") as tar_file:
182
- tar_file.extractall(directory_path)
182
+ # use 'data' to ensure no security risks are imposed by the archive files
183
+ # see: https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extractall
184
+ tar_file.extractall(directory_path, filter="data")
183
185
 
184
186
  return str(directory_path)
185
187
 
@@ -16,19 +16,15 @@ import json
16
16
  import os
17
17
  import urllib
18
18
  from collections import namedtuple
19
- from datetime import datetime
20
- from http import HTTPStatus
21
19
  from urllib.parse import urlparse
22
20
 
23
21
  import kfp.dsl
24
22
  import requests
25
23
  import semver
26
- import urllib3
27
24
  import v3io
28
25
 
29
26
  import mlrun.errors
30
27
  from mlrun.config import config as mlconf
31
- from mlrun.errors import err_to_str
32
28
  from mlrun.utils import dict_to_json
33
29
 
34
30
  _cached_control_session = None
@@ -488,25 +484,6 @@ class V3ioStreamClient:
488
484
  return response.output.records
489
485
 
490
486
 
491
- def create_control_session(url, username, password):
492
- # for systems without production cert - silence no cert verification WARN
493
- urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
494
- if not username or not password:
495
- raise ValueError("cannot create session key, missing username or password")
496
-
497
- session = requests.Session()
498
- session.auth = (username, password)
499
- try:
500
- auth = session.post(f"{url}/api/sessions", verify=False)
501
- except OSError as exc:
502
- raise OSError(f"error: cannot connect to {url}: {err_to_str(exc)}")
503
-
504
- if not auth.ok:
505
- raise OSError(f"failed to create session: {url}, {auth.text}")
506
-
507
- return auth.json()["data"]["id"]
508
-
509
-
510
487
  def is_iguazio_endpoint(endpoint_url: str) -> bool:
511
488
  # TODO: find a better heuristic
512
489
  return ".default-tenant." in endpoint_url
@@ -533,21 +510,6 @@ def is_iguazio_session_cookie(session_cookie: str) -> bool:
533
510
  return False
534
511
 
535
512
 
536
- def is_iguazio_system_2_10_or_above(dashboard_url):
537
- # for systems without production cert - silence no cert verification WARN
538
- urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
539
- response = requests.get(f"{dashboard_url}/api/external_versions", verify=False)
540
-
541
- if not response.ok:
542
- if response.status_code == HTTPStatus.NOT_FOUND.value:
543
- # in iguazio systems prior to 2.10 this endpoint didn't exist, so the api returns 404 cause endpoint not
544
- # found
545
- return False
546
- response.raise_for_status()
547
-
548
- return True
549
-
550
-
551
513
  # we assign the control session or access key to the password since this is iguazio auth scheme
552
514
  # (requests should be sent with username:control_session/access_key as auth header)
553
515
  def add_or_refresh_credentials(
@@ -577,33 +539,12 @@ def add_or_refresh_credentials(
577
539
  # (ideally if we could identify we're in enterprise we would have verify here that token and username have value)
578
540
  if not is_iguazio_endpoint(api_url):
579
541
  return "", "", token
580
- iguazio_dashboard_url = "https://dashboard" + api_url[api_url.find(".") :]
581
-
582
- # in 2.8 mlrun api is protected with control session, from 2.10 it's protected with access key
583
- is_access_key_auth = is_iguazio_system_2_10_or_above(iguazio_dashboard_url)
584
- if is_access_key_auth:
585
- if not username or not token:
586
- raise ValueError(
587
- "username and access key required to authenticate against iguazio system"
588
- )
589
- return username, token, ""
590
-
591
- if not username or not password:
592
- raise ValueError("username and password needed to create session")
593
-
594
- global _cached_control_session
595
- now = datetime.now()
596
- if _cached_control_session:
597
- if (
598
- _cached_control_session[2] == username
599
- and _cached_control_session[3] == password
600
- and (now - _cached_control_session[1]).seconds < 20 * 60 * 60
601
- ):
602
- return _cached_control_session[2], _cached_control_session[0], ""
603
-
604
- control_session = create_control_session(iguazio_dashboard_url, username, password)
605
- _cached_control_session = (control_session, now, username, password)
606
- return username, control_session, ""
542
+
543
+ if not username or not token:
544
+ raise ValueError(
545
+ "username and access key required to authenticate against iguazio system"
546
+ )
547
+ return username, token, ""
607
548
 
608
549
 
609
550
  def parse_path(url, suffix="/"):
@@ -69,16 +69,16 @@ class WorkflowSpec(mlrun.model.ModelObj):
69
69
 
70
70
  def __init__(
71
71
  self,
72
- engine=None,
73
- code=None,
74
- path=None,
75
- args=None,
76
- name=None,
77
- handler=None,
78
- args_schema: dict = None,
72
+ engine: typing.Optional[str] = None,
73
+ code: typing.Optional[str] = None,
74
+ path: typing.Optional[str] = None,
75
+ args: typing.Optional[dict] = None,
76
+ name: typing.Optional[str] = None,
77
+ handler: typing.Optional[str] = None,
78
+ args_schema: typing.Optional[dict] = None,
79
79
  schedule: typing.Union[str, mlrun.common.schemas.ScheduleCronTrigger] = None,
80
- cleanup_ttl: int = None,
81
- image: str = None,
80
+ cleanup_ttl: typing.Optional[int] = None,
81
+ image: typing.Optional[str] = None,
82
82
  ):
83
83
  self.engine = engine
84
84
  self.code = code
@@ -401,6 +401,9 @@ def enrich_function_object(
401
401
  else:
402
402
  f.spec.build.source = project.spec.source
403
403
  f.spec.build.load_source_on_run = project.spec.load_source_on_run
404
+ f.spec.build.source_code_target_dir = (
405
+ project.spec.build.source_code_target_dir
406
+ )
404
407
  f.spec.workdir = project.spec.workdir or project.spec.subpath
405
408
  f.prepare_image_for_deploy()
406
409
 
@@ -862,6 +865,11 @@ class _RemoteRunner(_PipelineRunner):
862
865
  )
863
866
  return
864
867
 
868
+ logger.debug(
869
+ "Workflow submitted, waiting for pipeline run to start",
870
+ workflow_name=workflow_response.name,
871
+ )
872
+
865
873
  # Getting workflow id from run:
866
874
  response = retry_until_successful(
867
875
  1,
@@ -988,6 +996,7 @@ def load_and_run(
988
996
  cleanup_ttl: int = None,
989
997
  load_only: bool = False,
990
998
  wait_for_completion: bool = False,
999
+ project_context: str = None,
991
1000
  ):
992
1001
  """
993
1002
  Auxiliary function that the RemoteRunner run once or run every schedule.
@@ -1018,10 +1027,11 @@ def load_and_run(
1018
1027
  workflow and all its resources are deleted)
1019
1028
  :param load_only: for just loading the project, inner use.
1020
1029
  :param wait_for_completion: wait for workflow completion before returning
1030
+ :param project_context: project context path (used for loading the project)
1021
1031
  """
1022
1032
  try:
1023
1033
  project = mlrun.load_project(
1024
- context=f"./{project_name}",
1034
+ context=project_context or f"./{project_name}",
1025
1035
  url=url,
1026
1036
  name=project_name,
1027
1037
  init_git=init_git,
@@ -1053,7 +1063,7 @@ def load_and_run(
1053
1063
 
1054
1064
  raise error
1055
1065
 
1056
- context.logger.info(f"Loaded project {project.name} from remote successfully")
1066
+ context.logger.info(f"Loaded project {project.name} successfully")
1057
1067
 
1058
1068
  if load_only:
1059
1069
  return
mlrun/projects/project.py CHANGED
@@ -24,7 +24,7 @@ import typing
24
24
  import uuid
25
25
  import warnings
26
26
  import zipfile
27
- from os import environ, makedirs, path, remove
27
+ from os import environ, makedirs, path
28
28
  from typing import Callable, Dict, List, Optional, Union
29
29
 
30
30
  import dotenv
@@ -605,9 +605,14 @@ def _load_project_dir(context, name="", subpath=""):
605
605
  # If there is a setup script do not force having project.yaml file
606
606
  project = MlrunProject()
607
607
  else:
608
- raise mlrun.errors.MLRunNotFoundError(
609
- "project or function YAML not found in path"
608
+ message = "Project or function YAML not found in path"
609
+ logger.error(
610
+ message,
611
+ context=context,
612
+ name=name,
613
+ subpath=subpath,
610
614
  )
615
+ raise mlrun.errors.MLRunNotFoundError(message)
611
616
 
612
617
  project.spec.context = context
613
618
  project.metadata.name = name or project.metadata.name
@@ -1235,20 +1240,20 @@ class MlrunProject(ModelObj):
1235
1240
  self,
1236
1241
  name,
1237
1242
  workflow_path: str,
1238
- embed=False,
1239
- engine=None,
1240
- args_schema: typing.List[EntrypointParam] = None,
1241
- handler=None,
1243
+ embed: bool = False,
1244
+ engine: Optional[str] = None,
1245
+ args_schema: list[EntrypointParam] = None,
1246
+ handler: Optional[str] = None,
1242
1247
  schedule: typing.Union[str, mlrun.common.schemas.ScheduleCronTrigger] = None,
1243
- ttl=None,
1244
- image: str = None,
1248
+ ttl: Optional[int] = None,
1249
+ image: Optional[str] = None,
1245
1250
  **args,
1246
1251
  ):
1247
1252
  """Add or update a workflow, specify a name and the code path
1248
1253
 
1249
1254
  :param name: Name of the workflow
1250
1255
  :param workflow_path: URL (remote) / Path (absolute or relative to the project code path i.e.
1251
- <project.spec.get_code_path()>/<workflow_path>) for the workflow file.
1256
+ <project.spec.get_code_path()>/<workflow_path>) for the workflow file.
1252
1257
  :param embed: Add the workflow code into the project.yaml
1253
1258
  :param engine: Workflow processing engine ("kfp", "local", "remote" or "remote:local")
1254
1259
  :param args_schema: List of arg schema definitions (:py:class`~mlrun.model.EntrypointParam`)
@@ -2595,40 +2600,45 @@ class MlrunProject(ModelObj):
2595
2600
  cleanup_ttl: int = None,
2596
2601
  notifications: typing.List[mlrun.model.Notification] = None,
2597
2602
  ) -> _PipelineRunStatus:
2598
- """run a workflow using kubeflow pipelines
2603
+ """Run a workflow using kubeflow pipelines
2599
2604
 
2600
- :param name: name of the workflow
2605
+ :param name: Name of the workflow
2601
2606
  :param workflow_path:
2602
- url to a workflow file, if not a project workflow
2607
+ URL to a workflow file, if not a project workflow
2603
2608
  :param arguments:
2604
- kubeflow pipelines arguments (parameters)
2609
+ Kubeflow pipelines arguments (parameters)
2605
2610
  :param artifact_path:
2606
- target path/url for workflow artifacts, the string
2611
+ Target path/url for workflow artifacts, the string
2607
2612
  '{{workflow.uid}}' will be replaced by workflow id
2608
2613
  :param workflow_handler:
2609
- workflow function handler (for running workflow function directly)
2610
- :param namespace: kubernetes namespace if other than default
2611
- :param sync: force functions sync before run
2612
- :param watch: wait for pipeline completion
2613
- :param dirty: allow running the workflow when the git repo is dirty
2614
- :param engine: workflow engine running the workflow.
2615
- supported values are 'kfp' (default), 'local' or 'remote'.
2616
- for setting engine for remote running use 'remote:local' or 'remote:kfp'.
2617
- :param local: run local pipeline with local functions (set local=True in function.run())
2614
+ Workflow function handler (for running workflow function directly)
2615
+ :param namespace: Kubernetes namespace if other than default
2616
+ :param sync: Force functions sync before run
2617
+ :param watch: Wait for pipeline completion
2618
+ :param dirty: Allow running the workflow when the git repo is dirty
2619
+ :param engine: Workflow engine running the workflow.
2620
+ Supported values are 'kfp' (default), 'local' or 'remote'.
2621
+ For setting engine for remote running use 'remote:local' or 'remote:kfp'.
2622
+ :param local: Run local pipeline with local functions (set local=True in function.run())
2618
2623
  :param schedule: ScheduleCronTrigger class instance or a standard crontab expression string
2619
2624
  (which will be converted to the class using its `from_crontab` constructor),
2620
2625
  see this link for help:
2621
2626
  https://apscheduler.readthedocs.io/en/3.x/modules/triggers/cron.html#module-apscheduler.triggers.cron
2622
2627
  for using the pre-defined workflow's schedule, set `schedule=True`
2623
- :param timeout: timeout in seconds to wait for pipeline completion (watch will be activated)
2624
- :param source: remote source to use instead of the actual `project.spec.source` (used when engine is remote).
2625
- for other engines the source is to validate that the code is up-to-date
2628
+ :param timeout: Timeout in seconds to wait for pipeline completion (watch will be activated)
2629
+ :param source: Source to use instead of the actual `project.spec.source` (used when engine is remote).
2630
+ Can be a one of:
2631
+ 1. Remote URL which is loaded dynamically to the workflow runner.
2632
+ 2. A path to the project's context on the workflow runner's image.
2633
+ Path can be absolute or relative to `project.spec.build.source_code_target_dir` if defined
2634
+ (enriched when building a project image with source, see `MlrunProject.build_image`).
2635
+ For other engines the source is used to validate that the code is up-to-date.
2626
2636
  :param cleanup_ttl:
2627
- pipeline cleanup ttl in secs (time to wait after workflow completion, at which point the
2628
- workflow and all its resources are deleted)
2637
+ Pipeline cleanup ttl in secs (time to wait after workflow completion, at which point the
2638
+ Workflow and all its resources are deleted)
2629
2639
  :param notifications:
2630
- list of notifications to send for workflow completion
2631
- :returns: run id
2640
+ List of notifications to send for workflow completion
2641
+ :returns: Run id
2632
2642
  """
2633
2643
 
2634
2644
  arguments = arguments or {}
@@ -2775,7 +2785,7 @@ class MlrunProject(ModelObj):
2775
2785
  def export(self, filepath=None, include_files: str = None):
2776
2786
  """save the project object into a yaml file or zip archive (default to project.yaml)
2777
2787
 
2778
- By default the project object is exported to a yaml file, when the filepath suffix is '.zip'
2788
+ By default, the project object is exported to a yaml file, when the filepath suffix is '.zip'
2779
2789
  the project context dir (code files) are also copied into the zip, the archive path can include
2780
2790
  DataItem urls (for remote object storage, e.g. s3://<bucket>/<path>).
2781
2791
 
@@ -2800,19 +2810,19 @@ class MlrunProject(ModelObj):
2800
2810
 
2801
2811
  if archive_code:
2802
2812
  files_filter = include_files or "**"
2803
- tmp_path = None
2804
- if "://" in filepath:
2805
- tmp_path = tempfile.mktemp(".zip")
2806
- zipf = zipfile.ZipFile(tmp_path or filepath, "w")
2807
- for file_path in glob.iglob(
2808
- f"{project_dir}/{files_filter}", recursive=True
2809
- ):
2810
- write_path = pathlib.Path(file_path)
2811
- zipf.write(write_path, arcname=write_path.relative_to(project_dir))
2812
- zipf.close()
2813
- if tmp_path:
2814
- mlrun.get_dataitem(filepath).upload(tmp_path)
2815
- remove(tmp_path)
2813
+ with tempfile.NamedTemporaryFile(suffix=".zip") as f:
2814
+ remote_file = "://" in filepath
2815
+ fpath = f.name if remote_file else filepath
2816
+ with zipfile.ZipFile(fpath, "w") as zipf:
2817
+ for file_path in glob.iglob(
2818
+ f"{project_dir}/{files_filter}", recursive=True
2819
+ ):
2820
+ write_path = pathlib.Path(file_path)
2821
+ zipf.write(
2822
+ write_path, arcname=write_path.relative_to(project_dir)
2823
+ )
2824
+ if remote_file:
2825
+ mlrun.get_dataitem(filepath).upload(zipf.filename)
2816
2826
 
2817
2827
  def set_model_monitoring_credentials(
2818
2828
  self,
@@ -3027,6 +3037,7 @@ class MlrunProject(ModelObj):
3027
3037
  requirements_file: str = None,
3028
3038
  builder_env: dict = None,
3029
3039
  extra_args: str = None,
3040
+ source_code_target_dir: str = None,
3030
3041
  ):
3031
3042
  """specify builder configuration for the project
3032
3043
 
@@ -3047,6 +3058,8 @@ class MlrunProject(ModelObj):
3047
3058
  e.g. builder_env={"GIT_TOKEN": token}, does not work yet in KFP
3048
3059
  :param extra_args: A string containing additional builder arguments in the format of command-line options,
3049
3060
  e.g. extra_args="--skip-tls-verify --build-arg A=val"
3061
+ :param source_code_target_dir: Path on the image where source code would be extracted
3062
+ (by default `/home/mlrun_code`)
3050
3063
  """
3051
3064
  if not overwrite_build_params:
3052
3065
  # TODO: change overwrite_build_params default to True in 1.8.0
@@ -3070,6 +3083,7 @@ class MlrunProject(ModelObj):
3070
3083
  overwrite=overwrite_build_params,
3071
3084
  builder_env=builder_env,
3072
3085
  extra_args=extra_args,
3086
+ source_code_target_dir=source_code_target_dir,
3073
3087
  )
3074
3088
 
3075
3089
  if set_as_default and image != self.default_image:
@@ -3116,7 +3130,7 @@ class MlrunProject(ModelObj):
3116
3130
  * False: The new params are merged with the existing
3117
3131
  * True: The existing params are replaced by the new ones
3118
3132
  :param extra_args: A string containing additional builder arguments in the format of command-line options,
3119
- e.g. extra_args="--skip-tls-verify --build-arg A=val"r
3133
+ e.g. extra_args="--skip-tls-verify --build-arg A=val"
3120
3134
  :param target_dir: Path on the image where source code would be extracted (by default `/home/mlrun_code`)
3121
3135
  """
3122
3136
  if not base_image:
@@ -3184,6 +3198,11 @@ class MlrunProject(ModelObj):
3184
3198
  force_build=True,
3185
3199
  )
3186
3200
 
3201
+ # Get the enriched target dir from the function
3202
+ self.spec.build.source_code_target_dir = (
3203
+ function.spec.build.source_code_target_dir
3204
+ )
3205
+
3187
3206
  try:
3188
3207
  mlrun.db.get_run_db(secrets=self._secrets).delete_function(
3189
3208
  name=function.metadata.name
mlrun/runtimes/base.py CHANGED
@@ -15,6 +15,7 @@ import enum
15
15
  import http
16
16
  import re
17
17
  import typing
18
+ import warnings
18
19
  from base64 import b64encode
19
20
  from os import environ
20
21
  from typing import Callable, Dict, List, Optional, Union
@@ -124,7 +125,7 @@ class FunctionSpec(ModelObj):
124
125
  self.allow_empty_resources = None
125
126
  # the build.source is cloned/extracted to the specified clone_target_dir
126
127
  # if a relative path is specified, it will be enriched with a temp dir path
127
- self.clone_target_dir = clone_target_dir or ""
128
+ self._clone_target_dir = clone_target_dir or None
128
129
 
129
130
  @property
130
131
  def build(self) -> ImageBuilder:
@@ -134,6 +135,24 @@ class FunctionSpec(ModelObj):
134
135
  def build(self, build):
135
136
  self._build = self._verify_dict(build, "build", ImageBuilder)
136
137
 
138
+ @property
139
+ def clone_target_dir(self):
140
+ warnings.warn(
141
+ "The clone_target_dir attribute is deprecated in 1.6.2 and will be removed in 1.8.0. "
142
+ "Use spec.build.source_code_target_dir instead.",
143
+ FutureWarning,
144
+ )
145
+ return self.build.source_code_target_dir
146
+
147
+ @clone_target_dir.setter
148
+ def clone_target_dir(self, clone_target_dir):
149
+ warnings.warn(
150
+ "The clone_target_dir attribute is deprecated in 1.6.2 and will be removed in 1.8.0. "
151
+ "Use spec.build.source_code_target_dir instead.",
152
+ FutureWarning,
153
+ )
154
+ self.build.source_code_target_dir = clone_target_dir
155
+
137
156
  def enrich_function_preemption_spec(self):
138
157
  pass
139
158
 
@@ -432,15 +432,15 @@ class RemoteRuntime(KubeResource):
432
432
  raise ValueError(
433
433
  "gateway timeout must be greater than the worker timeout"
434
434
  )
435
- annotations[
436
- "nginx.ingress.kubernetes.io/proxy-connect-timeout"
437
- ] = f"{gateway_timeout}"
438
- annotations[
439
- "nginx.ingress.kubernetes.io/proxy-read-timeout"
440
- ] = f"{gateway_timeout}"
441
- annotations[
442
- "nginx.ingress.kubernetes.io/proxy-send-timeout"
443
- ] = f"{gateway_timeout}"
435
+ annotations["nginx.ingress.kubernetes.io/proxy-connect-timeout"] = (
436
+ f"{gateway_timeout}"
437
+ )
438
+ annotations["nginx.ingress.kubernetes.io/proxy-read-timeout"] = (
439
+ f"{gateway_timeout}"
440
+ )
441
+ annotations["nginx.ingress.kubernetes.io/proxy-send-timeout"] = (
442
+ f"{gateway_timeout}"
443
+ )
444
444
 
445
445
  trigger = nuclio.HttpTrigger(
446
446
  workers=workers,
mlrun/runtimes/kubejob.py CHANGED
@@ -73,7 +73,7 @@ class KubejobRuntime(KubeResource):
73
73
  if workdir:
74
74
  self.spec.workdir = workdir
75
75
  if target_dir:
76
- self.spec.clone_target_dir = target_dir
76
+ self.spec.build.source_code_target_dir = target_dir
77
77
 
78
78
  self.spec.build.load_source_on_run = pull_at_runtime
79
79
  if (
@@ -232,8 +232,10 @@ class KubejobRuntime(KubeResource):
232
232
  self.spec.build.base_image = self.spec.build.base_image or get_in(
233
233
  data, "data.spec.build.base_image"
234
234
  )
235
- # get the clone target dir in case it was enriched due to loading source
236
- self.spec.clone_target_dir = get_in(data, "data.spec.clone_target_dir")
235
+ # Get the source target dir in case it was enriched due to loading source
236
+ self.spec.build.source_code_target_dir = get_in(
237
+ data, "data.spec.build.source_code_target_dir"
238
+ ) or get_in(data, "data.spec.clone_target_dir")
237
239
  ready = data.get("ready", False)
238
240
  if not ready:
239
241
  logger.info(
mlrun/runtimes/local.py CHANGED
@@ -218,7 +218,7 @@ class LocalRuntime(BaseRuntime, ParallelRunner):
218
218
  if workdir:
219
219
  self.spec.workdir = workdir
220
220
  if target_dir:
221
- self.spec.clone_target_dir = target_dir
221
+ self.spec.build.source_code_target_dir = target_dir
222
222
 
223
223
  def is_deployed(self):
224
224
  return True
@@ -240,7 +240,7 @@ class LocalRuntime(BaseRuntime, ParallelRunner):
240
240
  if self.spec.build.source and not hasattr(self, "_is_run_local"):
241
241
  target_dir = extract_source(
242
242
  self.spec.build.source,
243
- self.spec.clone_target_dir,
243
+ self.spec.build.source_code_target_dir,
244
244
  secrets=execution._secrets_manager,
245
245
  )
246
246
  if workdir and not workdir.startswith("/"):
@@ -196,13 +196,13 @@ class AbstractMPIJobRuntime(KubejobRuntime, abc.ABC):
196
196
  if steps_per_sample is not None:
197
197
  horovod_autotune_settings["autotune-steps-per-sample"] = steps_per_sample
198
198
  if bayes_opt_max_samples is not None:
199
- horovod_autotune_settings[
200
- "autotune-bayes-opt-max-samples"
201
- ] = bayes_opt_max_samples
199
+ horovod_autotune_settings["autotune-bayes-opt-max-samples"] = (
200
+ bayes_opt_max_samples
201
+ )
202
202
  if gaussian_process_noise is not None:
203
- horovod_autotune_settings[
204
- "autotune-gaussian-process-noise"
205
- ] = gaussian_process_noise
203
+ horovod_autotune_settings["autotune-gaussian-process-noise"] = (
204
+ gaussian_process_noise
205
+ )
206
206
 
207
207
  self.set_envs(horovod_autotune_settings)
208
208
 
mlrun/runtimes/pod.py CHANGED
@@ -430,9 +430,9 @@ class KubeResourceSpec(FunctionSpec):
430
430
  )
431
431
  is None
432
432
  ):
433
- resources[resource_requirement][
434
- resource_type
435
- ] = default_resources[resource_requirement][resource_type]
433
+ resources[resource_requirement][resource_type] = (
434
+ default_resources[resource_requirement][resource_type]
435
+ )
436
436
  # This enables the user to define that no defaults would be applied on the resources
437
437
  elif resources == {}:
438
438
  return resources
mlrun/runtimes/serving.py CHANGED
@@ -523,9 +523,9 @@ class ServingRuntime(RemoteRuntime):
523
523
  function_object.metadata.tag = self.metadata.tag
524
524
 
525
525
  function_object.metadata.labels = function_object.metadata.labels or {}
526
- function_object.metadata.labels[
527
- "mlrun/parent-function"
528
- ] = self.metadata.name
526
+ function_object.metadata.labels["mlrun/parent-function"] = (
527
+ self.metadata.name
528
+ )
529
529
  function_object._is_child_function = True
530
530
  if not function_object.spec.graph:
531
531
  # copy the current graph only if the child doesnt have a graph of his own
@@ -345,9 +345,9 @@ class Spark3JobSpec(KubeResourceSpec):
345
345
  )
346
346
  is None
347
347
  ):
348
- resources[resource_requirement][
349
- resource_type
350
- ] = default_resources[resource_requirement][resource_type]
348
+ resources[resource_requirement][resource_type] = (
349
+ default_resources[resource_requirement][resource_type]
350
+ )
351
351
  else:
352
352
  resources = default_resources
353
353
 
mlrun/serving/remote.py CHANGED
@@ -21,6 +21,7 @@ import storey
21
21
  from storey.flow import _ConcurrentJobExecution
22
22
 
23
23
  import mlrun
24
+ import mlrun.config
24
25
  from mlrun.errors import err_to_str
25
26
  from mlrun.utils import logger
26
27
 
@@ -173,7 +174,8 @@ class RemoteStep(storey.SendToHttp):
173
174
  if not self._session:
174
175
  self._session = mlrun.utils.HTTPSessionWithRetry(
175
176
  self.retries,
176
- self.backoff_factor or mlrun.mlconf.http_retry_defaults.backoff_factor,
177
+ self.backoff_factor
178
+ or mlrun.config.config.http_retry_defaults.backoff_factor,
177
179
  retry_on_exception=False,
178
180
  retry_on_status=self.retries > 0,
179
181
  retry_on_post=True,
@@ -185,7 +187,7 @@ class RemoteStep(storey.SendToHttp):
185
187
  resp = self._session.request(
186
188
  method,
187
189
  url,
188
- verify=False,
190
+ verify=mlrun.config.config.httpdb.http.verify,
189
191
  headers=headers,
190
192
  data=body,
191
193
  timeout=self.timeout,
mlrun/utils/async_http.py CHANGED
@@ -139,9 +139,9 @@ class _CustomRequestContext(_RequestContext):
139
139
 
140
140
  # enrich user agent
141
141
  # will help traceability and debugging
142
- headers[
143
- aiohttp.hdrs.USER_AGENT
144
- ] = f"{aiohttp.http.SERVER_SOFTWARE} mlrun/{config.version}"
142
+ headers[aiohttp.hdrs.USER_AGENT] = (
143
+ f"{aiohttp.http.SERVER_SOFTWARE} mlrun/{config.version}"
144
+ )
145
145
 
146
146
  response: typing.Optional[
147
147
  aiohttp.ClientResponse
mlrun/utils/helpers.py CHANGED
@@ -1622,3 +1622,11 @@ def get_local_file_schema() -> List:
1622
1622
  # The expression `list(string.ascii_lowercase)` generates a list of lowercase alphabets,
1623
1623
  # which corresponds to drive letters in Windows file paths such as `C:/Windows/path`.
1624
1624
  return ["file"] + list(string.ascii_lowercase)
1625
+
1626
+
1627
+ def is_safe_path(base, filepath, is_symlink=False):
1628
+ # Avoid path traversal attacks by ensuring that the path is safe
1629
+ resolved_filepath = (
1630
+ os.path.abspath(filepath) if not is_symlink else os.path.realpath(filepath)
1631
+ )
1632
+ return base == os.path.commonpath((base, resolved_filepath))
mlrun/utils/http.py CHANGED
@@ -110,9 +110,9 @@ class HTTPSessionWithRetry(requests.Session):
110
110
  def request(self, method, url, **kwargs):
111
111
  retry_count = 0
112
112
  kwargs.setdefault("headers", {})
113
- kwargs["headers"][
114
- "User-Agent"
115
- ] = f"{requests.utils.default_user_agent()} mlrun/{config.version}"
113
+ kwargs["headers"]["User-Agent"] = (
114
+ f"{requests.utils.default_user_agent()} mlrun/{config.version}"
115
+ )
116
116
  while True:
117
117
  try:
118
118
  response = super().request(method, url, **kwargs)