mlrun 1.10.0rc40__py3-none-any.whl → 1.11.0rc16__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 (150) hide show
  1. mlrun/__init__.py +3 -2
  2. mlrun/__main__.py +0 -4
  3. mlrun/artifacts/dataset.py +2 -2
  4. mlrun/artifacts/plots.py +1 -1
  5. mlrun/{model_monitoring/db/tsdb/tdengine → auth}/__init__.py +2 -3
  6. mlrun/auth/nuclio.py +89 -0
  7. mlrun/auth/providers.py +429 -0
  8. mlrun/auth/utils.py +415 -0
  9. mlrun/common/constants.py +7 -0
  10. mlrun/common/model_monitoring/helpers.py +41 -4
  11. mlrun/common/runtimes/constants.py +28 -0
  12. mlrun/common/schemas/__init__.py +13 -3
  13. mlrun/common/schemas/alert.py +2 -2
  14. mlrun/common/schemas/api_gateway.py +3 -0
  15. mlrun/common/schemas/auth.py +10 -10
  16. mlrun/common/schemas/client_spec.py +4 -0
  17. mlrun/common/schemas/constants.py +25 -0
  18. mlrun/common/schemas/frontend_spec.py +1 -8
  19. mlrun/common/schemas/function.py +24 -0
  20. mlrun/common/schemas/hub.py +3 -2
  21. mlrun/common/schemas/model_monitoring/__init__.py +1 -1
  22. mlrun/common/schemas/model_monitoring/constants.py +2 -2
  23. mlrun/common/schemas/secret.py +17 -2
  24. mlrun/common/secrets.py +95 -1
  25. mlrun/common/types.py +10 -10
  26. mlrun/config.py +53 -15
  27. mlrun/data_types/infer.py +2 -2
  28. mlrun/datastore/__init__.py +2 -3
  29. mlrun/datastore/base.py +274 -10
  30. mlrun/datastore/datastore.py +1 -1
  31. mlrun/datastore/datastore_profile.py +49 -17
  32. mlrun/datastore/model_provider/huggingface_provider.py +6 -2
  33. mlrun/datastore/model_provider/model_provider.py +2 -2
  34. mlrun/datastore/model_provider/openai_provider.py +2 -2
  35. mlrun/datastore/s3.py +15 -16
  36. mlrun/datastore/sources.py +1 -1
  37. mlrun/datastore/store_resources.py +4 -4
  38. mlrun/datastore/storeytargets.py +16 -10
  39. mlrun/datastore/targets.py +1 -1
  40. mlrun/datastore/utils.py +16 -3
  41. mlrun/datastore/v3io.py +1 -1
  42. mlrun/db/base.py +36 -12
  43. mlrun/db/httpdb.py +316 -101
  44. mlrun/db/nopdb.py +29 -11
  45. mlrun/errors.py +4 -2
  46. mlrun/execution.py +11 -12
  47. mlrun/feature_store/api.py +1 -1
  48. mlrun/feature_store/common.py +1 -1
  49. mlrun/feature_store/feature_vector_utils.py +1 -1
  50. mlrun/feature_store/steps.py +8 -6
  51. mlrun/frameworks/_common/utils.py +3 -3
  52. mlrun/frameworks/_dl_common/loggers/logger.py +1 -1
  53. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +2 -1
  54. mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +1 -1
  55. mlrun/frameworks/_ml_common/utils.py +2 -1
  56. mlrun/frameworks/auto_mlrun/auto_mlrun.py +4 -3
  57. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +2 -1
  58. mlrun/frameworks/onnx/dataset.py +2 -1
  59. mlrun/frameworks/onnx/mlrun_interface.py +2 -1
  60. mlrun/frameworks/pytorch/callbacks/logging_callback.py +5 -4
  61. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +2 -1
  62. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +2 -1
  63. mlrun/frameworks/pytorch/utils.py +2 -1
  64. mlrun/frameworks/sklearn/metric.py +2 -1
  65. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +5 -4
  66. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +2 -1
  67. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +2 -1
  68. mlrun/hub/__init__.py +37 -0
  69. mlrun/hub/base.py +142 -0
  70. mlrun/hub/module.py +67 -76
  71. mlrun/hub/step.py +113 -0
  72. mlrun/launcher/base.py +2 -1
  73. mlrun/launcher/local.py +2 -1
  74. mlrun/model.py +12 -2
  75. mlrun/model_monitoring/__init__.py +0 -1
  76. mlrun/model_monitoring/api.py +2 -2
  77. mlrun/model_monitoring/applications/base.py +20 -6
  78. mlrun/model_monitoring/applications/context.py +1 -0
  79. mlrun/model_monitoring/controller.py +7 -17
  80. mlrun/model_monitoring/db/_schedules.py +2 -16
  81. mlrun/model_monitoring/db/_stats.py +2 -13
  82. mlrun/model_monitoring/db/tsdb/__init__.py +9 -7
  83. mlrun/model_monitoring/db/tsdb/base.py +2 -4
  84. mlrun/model_monitoring/db/tsdb/preaggregate.py +234 -0
  85. mlrun/model_monitoring/db/tsdb/stream_graph_steps.py +63 -0
  86. mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_metrics_queries.py +414 -0
  87. mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_predictions_queries.py +376 -0
  88. mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_results_queries.py +590 -0
  89. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_connection.py +434 -0
  90. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_connector.py +541 -0
  91. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_operations.py +808 -0
  92. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_schema.py +502 -0
  93. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_stream.py +163 -0
  94. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_stream_graph_steps.py +60 -0
  95. mlrun/model_monitoring/db/tsdb/timescaledb/utils/timescaledb_dataframe_processor.py +141 -0
  96. mlrun/model_monitoring/db/tsdb/timescaledb/utils/timescaledb_query_builder.py +585 -0
  97. mlrun/model_monitoring/db/tsdb/timescaledb/writer_graph_steps.py +73 -0
  98. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +4 -6
  99. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +147 -79
  100. mlrun/model_monitoring/features_drift_table.py +2 -1
  101. mlrun/model_monitoring/helpers.py +2 -1
  102. mlrun/model_monitoring/stream_processing.py +18 -16
  103. mlrun/model_monitoring/writer.py +4 -3
  104. mlrun/package/__init__.py +2 -1
  105. mlrun/platforms/__init__.py +0 -44
  106. mlrun/platforms/iguazio.py +1 -1
  107. mlrun/projects/operations.py +11 -10
  108. mlrun/projects/project.py +81 -82
  109. mlrun/run.py +4 -7
  110. mlrun/runtimes/__init__.py +2 -204
  111. mlrun/runtimes/base.py +89 -21
  112. mlrun/runtimes/constants.py +225 -0
  113. mlrun/runtimes/daskjob.py +4 -2
  114. mlrun/runtimes/databricks_job/databricks_runtime.py +2 -1
  115. mlrun/runtimes/mounts.py +5 -0
  116. mlrun/runtimes/nuclio/__init__.py +12 -8
  117. mlrun/runtimes/nuclio/api_gateway.py +36 -6
  118. mlrun/runtimes/nuclio/application/application.py +200 -32
  119. mlrun/runtimes/nuclio/function.py +154 -49
  120. mlrun/runtimes/nuclio/serving.py +55 -42
  121. mlrun/runtimes/pod.py +59 -10
  122. mlrun/secrets.py +46 -2
  123. mlrun/serving/__init__.py +2 -0
  124. mlrun/serving/remote.py +5 -5
  125. mlrun/serving/routers.py +3 -3
  126. mlrun/serving/server.py +46 -43
  127. mlrun/serving/serving_wrapper.py +6 -2
  128. mlrun/serving/states.py +554 -207
  129. mlrun/serving/steps.py +1 -1
  130. mlrun/serving/system_steps.py +42 -33
  131. mlrun/track/trackers/mlflow_tracker.py +29 -31
  132. mlrun/utils/helpers.py +89 -16
  133. mlrun/utils/http.py +9 -2
  134. mlrun/utils/notifications/notification/git.py +1 -1
  135. mlrun/utils/notifications/notification/mail.py +39 -16
  136. mlrun/utils/notifications/notification_pusher.py +2 -2
  137. mlrun/utils/version/version.json +2 -2
  138. mlrun/utils/version/version.py +3 -4
  139. {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/METADATA +39 -49
  140. {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/RECORD +144 -130
  141. mlrun/db/auth_utils.py +0 -152
  142. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +0 -343
  143. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +0 -75
  144. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py +0 -281
  145. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +0 -1368
  146. mlrun/model_monitoring/db/tsdb/tdengine/writer_graph_steps.py +0 -51
  147. {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/WHEEL +0 -0
  148. {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/entry_points.txt +0 -0
  149. {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/licenses/LICENSE +0 -0
  150. {mlrun-1.10.0rc40.dist-info → mlrun-1.11.0rc16.dist-info}/top_level.txt +0 -0
mlrun/runtimes/base.py CHANGED
@@ -16,8 +16,9 @@ import http
16
16
  import re
17
17
  import typing
18
18
  import warnings
19
+ from collections.abc import Callable
19
20
  from os import environ
20
- from typing import Callable, Optional, Union
21
+ from typing import Optional, Union
21
22
 
22
23
  import requests.exceptions
23
24
  from nuclio.build import mlrun_footer
@@ -30,6 +31,7 @@ import mlrun.common.schemas
30
31
  import mlrun.common.schemas.model_monitoring.constants as mm_constants
31
32
  import mlrun.errors
32
33
  import mlrun.launcher.factory
34
+ import mlrun.runtimes
33
35
  import mlrun.utils.helpers
34
36
  import mlrun.utils.notifications
35
37
  import mlrun.utils.regex
@@ -277,18 +279,6 @@ class BaseRuntime(ModelObj):
277
279
  mlrun.model.Credentials.generate_access_key
278
280
  )
279
281
 
280
- def generate_runtime_k8s_env(self, runobj: RunObject = None) -> list[dict]:
281
- """
282
- Prepares a runtime environment as it's expected by kubernetes.models.V1Container
283
-
284
- :param runobj: Run context object (RunObject) with run metadata and status
285
- :return: List of dicts with the structure {"name": "var_name", "value": "var_value"}
286
- """
287
- return [
288
- {"name": k, "value": v}
289
- for k, v in self._generate_runtime_env(runobj).items()
290
- ]
291
-
292
282
  def run(
293
283
  self,
294
284
  runspec: Optional[
@@ -394,8 +384,6 @@ class BaseRuntime(ModelObj):
394
384
  )
395
385
  output_path = output_path or out_path or artifact_path
396
386
 
397
- mlrun.utils.helpers.validate_function_name(self.metadata.name)
398
-
399
387
  launcher = mlrun.launcher.factory.LauncherFactory().create_launcher(
400
388
  self._is_remote, local=local, **launcher_kwargs
401
389
  )
@@ -443,13 +431,14 @@ class BaseRuntime(ModelObj):
443
431
  if task:
444
432
  return task.to_dict()
445
433
 
446
- def _generate_runtime_env(self, runobj: RunObject = None) -> dict:
434
+ def _generate_runtime_env(self, runobj: RunObject = None):
447
435
  """
448
- Prepares all available environment variables for usage on a runtime
449
- Data will be extracted from several sources and most of them are not guaranteed to be available
436
+ Prepares all available environment variables for usage on a runtime.
450
437
 
451
- :param runobj: Run context object (RunObject) with run metadata and status
452
- :return: Dictionary with all the variables that could be parsed
438
+ :param runobj: Optional run context object (RunObject) with run metadata and status
439
+ :return: Tuple of (runtime_env, external_source_env) where:
440
+ - runtime_env: Dict of {env_name: value} for standard env vars
441
+ - external_source_env: Dict of {env_name: value_from} for env vars with external sources
453
442
  """
454
443
  active_project = self.metadata.project or config.active_project
455
444
  runtime_env = {
@@ -457,6 +446,16 @@ class BaseRuntime(ModelObj):
457
446
  # TODO: Remove this in 1.12.0 as MLRUN_DEFAULT_PROJECT is deprecated and should not be injected anymore
458
447
  "MLRUN_DEFAULT_PROJECT": active_project,
459
448
  }
449
+
450
+ # Set auth session only for nuclio runtimes that have an access key
451
+ if (
452
+ self.kind in mlrun.runtimes.RuntimeKinds.nuclio_runtimes()
453
+ and self.metadata.credentials.access_key
454
+ ):
455
+ runtime_env[
456
+ mlrun.common.runtimes.constants.FunctionEnvironmentVariables.auth_session
457
+ ] = self.metadata.credentials.access_key
458
+
460
459
  if runobj:
461
460
  runtime_env["MLRUN_EXEC_CONFIG"] = runobj.to_json(
462
461
  exclude_notifications_params=True
@@ -471,7 +470,47 @@ class BaseRuntime(ModelObj):
471
470
  runtime_env["MLRUN_DBPATH"] = config.httpdb.api_url
472
471
  if self.metadata.namespace or config.namespace:
473
472
  runtime_env["MLRUN_NAMESPACE"] = self.metadata.namespace or config.namespace
474
- return runtime_env
473
+
474
+ external_source_env = self._generate_external_source_runtime_envs()
475
+
476
+ return runtime_env, external_source_env
477
+
478
+ def _generate_external_source_runtime_envs(self):
479
+ """
480
+ Returns non-static env vars to be added to the runtime pod/container.
481
+
482
+ :return: Dict of {env_name: value_from} for env vars with external sources (e.g., fieldRef)
483
+ """
484
+ return {
485
+ "MLRUN_RUNTIME_KIND": {
486
+ "fieldRef": {
487
+ "apiVersion": "v1",
488
+ "fieldPath": f"metadata.labels['{mlrun_constants.MLRunInternalLabels.mlrun_class}']",
489
+ }
490
+ },
491
+ }
492
+
493
+ def _generate_k8s_runtime_env(self, runobj: RunObject = None):
494
+ """
495
+ Generates runtime environment variables in Kubernetes format.
496
+
497
+ :param runobj: Optional run context object (RunObject) with run metadata and status
498
+ :return: List of env var dicts in K8s format:
499
+ - Standard envs: [{"name": key, "value": value}, ...]
500
+ - External source envs: [{"name": key, "valueFrom": value_from}, ...]
501
+ """
502
+ runtime_env, external_source_env = self._generate_runtime_env(runobj)
503
+
504
+ # Convert standard env vars to K8s format
505
+ k8s_env = [{"name": k, "value": v} for k, v in runtime_env.items()]
506
+
507
+ # Convert external source env vars to K8s format
508
+ k8s_external_env = [
509
+ {"name": k, "valueFrom": v} for k, v in external_source_env.items()
510
+ ]
511
+
512
+ k8s_env.extend(k8s_external_env)
513
+ return k8s_env
475
514
 
476
515
  @staticmethod
477
516
  def _handle_submit_job_http_error(error: requests.HTTPError):
@@ -949,5 +988,34 @@ class BaseRuntime(ModelObj):
949
988
  line += f", default={p['default']}"
950
989
  print(" " + line)
951
990
 
991
+ def remove_auth_secret_volumes(self):
992
+ secret_name_prefix = (
993
+ mlrun.mlconf.secret_stores.kubernetes.auth_secret_name.format(
994
+ hashed_access_key=""
995
+ )
996
+ )
997
+ volumes = self.spec.volumes or []
998
+ mounts = self.spec.volume_mounts or []
999
+
1000
+ volumes_to_remove = set()
1001
+
1002
+ # Identify volumes to remove
1003
+ for vol in volumes:
1004
+ secret_name = mlrun.utils.get_in(vol, "secret.secretName", "")
1005
+
1006
+ # Pattern of auth secret volumes
1007
+ if secret_name.startswith(secret_name_prefix):
1008
+ volumes_to_remove.add(vol["name"])
1009
+
1010
+ # Filter out only the matched volumes
1011
+ self.spec.volumes = [
1012
+ volume for volume in volumes if volume["name"] not in volumes_to_remove
1013
+ ]
1014
+
1015
+ # Filter out matching mounts
1016
+ self.spec.volume_mounts = [
1017
+ mount for mount in mounts if mount["name"] not in volumes_to_remove
1018
+ ]
1019
+
952
1020
  def skip_image_enrichment(self):
953
1021
  return False
@@ -0,0 +1,225 @@
1
+ # Copyright 2023 Iguazio
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import typing
16
+
17
+ import mlrun.runtimes.nuclio as nuclio_runtime
18
+ import mlrun.runtimes.nuclio.application as nuclio_application
19
+ import mlrun.runtimes.nuclio.serving as nuclio_serving
20
+
21
+
22
+ class RuntimeKinds:
23
+ remote = "remote"
24
+ nuclio = "nuclio"
25
+ dask = "dask"
26
+ job = "job"
27
+ spark = "spark"
28
+ remotespark = "remote-spark"
29
+ mpijob = "mpijob"
30
+ serving = "serving"
31
+ local = "local"
32
+ handler = "handler"
33
+ databricks = "databricks"
34
+ application = "application"
35
+
36
+ @staticmethod
37
+ def all():
38
+ return [
39
+ RuntimeKinds.remote,
40
+ RuntimeKinds.nuclio,
41
+ RuntimeKinds.serving,
42
+ RuntimeKinds.dask,
43
+ RuntimeKinds.job,
44
+ RuntimeKinds.spark,
45
+ RuntimeKinds.remotespark,
46
+ RuntimeKinds.mpijob,
47
+ RuntimeKinds.local,
48
+ RuntimeKinds.databricks,
49
+ RuntimeKinds.application,
50
+ ]
51
+
52
+ @staticmethod
53
+ def runtime_with_handlers():
54
+ return [
55
+ RuntimeKinds.dask,
56
+ RuntimeKinds.job,
57
+ RuntimeKinds.spark,
58
+ RuntimeKinds.remotespark,
59
+ RuntimeKinds.mpijob,
60
+ RuntimeKinds.databricks,
61
+ ]
62
+
63
+ @staticmethod
64
+ def abortable_runtimes():
65
+ return [
66
+ RuntimeKinds.job,
67
+ RuntimeKinds.spark,
68
+ RuntimeKinds.remotespark,
69
+ RuntimeKinds.mpijob,
70
+ RuntimeKinds.databricks,
71
+ RuntimeKinds.local,
72
+ RuntimeKinds.handler,
73
+ "",
74
+ ]
75
+
76
+ @staticmethod
77
+ def retriable_runtimes():
78
+ return [
79
+ RuntimeKinds.job,
80
+ ]
81
+
82
+ @staticmethod
83
+ def nuclio_runtimes():
84
+ return [
85
+ RuntimeKinds.remote,
86
+ RuntimeKinds.nuclio,
87
+ RuntimeKinds.serving,
88
+ RuntimeKinds.application,
89
+ ]
90
+
91
+ @staticmethod
92
+ def pure_nuclio_deployed_runtimes():
93
+ return [
94
+ RuntimeKinds.remote,
95
+ RuntimeKinds.nuclio,
96
+ RuntimeKinds.serving,
97
+ ]
98
+
99
+ @staticmethod
100
+ def handlerless_runtimes():
101
+ return [
102
+ RuntimeKinds.serving,
103
+ # Application runtime handler is internal reverse proxy
104
+ RuntimeKinds.application,
105
+ ]
106
+
107
+ @staticmethod
108
+ def local_runtimes():
109
+ return [
110
+ RuntimeKinds.local,
111
+ RuntimeKinds.handler,
112
+ ]
113
+
114
+ @staticmethod
115
+ def is_log_collectable_runtime(kind: typing.Optional[str]):
116
+ """
117
+ whether log collector can collect logs for that runtime
118
+ :param kind: kind name
119
+ :return: whether log collector can collect logs for that runtime
120
+ """
121
+ # if local run, the log collector doesn't support it as it is only supports k8s resources
122
+ # when runtime is local the client is responsible for logging the stdout of the run by using `log_std`
123
+ if RuntimeKinds.is_local_runtime(kind):
124
+ return False
125
+
126
+ if (
127
+ kind
128
+ not in [
129
+ # dask implementation is different from other runtimes, because few runs can be run against the same
130
+ # runtime resource, so collecting logs on that runtime resource won't be correct, the way we collect
131
+ # logs for dask is by using `log_std` on client side after we execute the code against the cluster,
132
+ # as submitting the run with the dask client will return the run stdout.
133
+ # For more information head to `DaskCluster._run`.
134
+ RuntimeKinds.dask
135
+ ]
136
+ + RuntimeKinds.nuclio_runtimes()
137
+ ):
138
+ return True
139
+
140
+ return False
141
+
142
+ @staticmethod
143
+ def is_local_runtime(kind):
144
+ # "" or None counted as local
145
+ if not kind or kind in RuntimeKinds.local_runtimes():
146
+ return True
147
+ return False
148
+
149
+ @staticmethod
150
+ def requires_k8s_name_validation(kind: str) -> bool:
151
+ """
152
+ Returns True if the runtime kind creates Kubernetes resources that use the function name.
153
+
154
+ Function names for k8s-deployed runtimes must conform to DNS-1123 label requirements:
155
+ - Lowercase alphanumeric characters or '-'
156
+ - Start and end with an alphanumeric character
157
+ - Maximum 63 characters
158
+
159
+ Local runtimes (local, handler) run on the local machine and don't create k8s resources,
160
+ so they don't require k8s naming validation.
161
+
162
+ :param kind: Runtime kind string (job, spark, serving, local, etc.)
163
+ :return: True if function name needs k8s DNS-1123 validation, False otherwise
164
+ """
165
+ return not RuntimeKinds.is_local_runtime(kind)
166
+
167
+ @staticmethod
168
+ def requires_absolute_artifacts_path(kind):
169
+ """
170
+ Returns True if the runtime kind requires absolute artifacts' path (i.e. is local), False otherwise.
171
+ """
172
+ if RuntimeKinds.is_local_runtime(kind):
173
+ return False
174
+
175
+ if kind not in [
176
+ # logging artifacts is done externally to the dask cluster by a client that can either run locally (in which
177
+ # case the path can be relative) or remotely (in which case the path must be absolute and will be passed
178
+ # to another run)
179
+ RuntimeKinds.dask
180
+ ]:
181
+ return True
182
+ return False
183
+
184
+ @staticmethod
185
+ def requires_image_name_for_execution(kind):
186
+ if RuntimeKinds.is_local_runtime(kind):
187
+ return False
188
+
189
+ # both spark and remote spark uses different mechanism for assigning images
190
+ return kind not in [RuntimeKinds.spark, RuntimeKinds.remotespark]
191
+
192
+ @staticmethod
193
+ def supports_from_notebook(kind):
194
+ return kind not in [RuntimeKinds.application]
195
+
196
+ @staticmethod
197
+ def resolve_nuclio_runtime(kind: str, sub_kind: str):
198
+ kind = kind.split(":")[0]
199
+ if kind not in RuntimeKinds.nuclio_runtimes():
200
+ raise ValueError(
201
+ f"Kind {kind} is not a nuclio runtime, "
202
+ f"available runtimes are {RuntimeKinds.nuclio_runtimes()}"
203
+ )
204
+
205
+ # These names are imported at module level below; referenced at call-time (no imports here).
206
+ if sub_kind == nuclio_serving.serving_subkind:
207
+ return nuclio_runtime.ServingRuntime()
208
+
209
+ if kind == RuntimeKinds.application:
210
+ return nuclio_application.ApplicationRuntime()
211
+
212
+ runtime = nuclio_runtime.RemoteRuntime()
213
+ runtime.spec.function_kind = sub_kind
214
+ return runtime
215
+
216
+ @staticmethod
217
+ def resolve_nuclio_sub_kind(kind: str):
218
+ is_nuclio = kind.startswith("nuclio")
219
+ sub_kind = kind[kind.find(":") + 1 :] if is_nuclio and ":" in kind else None
220
+ if kind == RuntimeKinds.serving:
221
+ is_nuclio = True
222
+ sub_kind = nuclio_serving.serving_subkind
223
+ elif kind == RuntimeKinds.application:
224
+ is_nuclio = True
225
+ return is_nuclio, sub_kind
mlrun/runtimes/daskjob.py CHANGED
@@ -15,8 +15,9 @@ import datetime
15
15
  import inspect
16
16
  import socket
17
17
  import time
18
+ from collections.abc import Callable
18
19
  from os import environ
19
- from typing import Callable, Optional, Union
20
+ from typing import Optional, Union
20
21
 
21
22
  import mlrun.common.schemas
22
23
  import mlrun.errors
@@ -551,7 +552,8 @@ class DaskCluster(KubejobRuntime):
551
552
 
552
553
  # TODO: investigate if the following instructions could overwrite the environment on any MLRun API Pod
553
554
  # Such action could result on race conditions against other runtimes and MLRun itself
554
- extra_env = self._generate_runtime_env(runobj)
555
+ extra_env, _ = self._generate_runtime_env(runobj)
556
+ # Since it runs locally, we don't need the external sources env vars
555
557
  environ.update(extra_env)
556
558
 
557
559
  context = MLClientCtx.from_dict(
@@ -14,7 +14,8 @@
14
14
  import typing
15
15
  from ast import FunctionDef, parse, unparse
16
16
  from base64 import b64decode
17
- from typing import Callable, Optional, Union
17
+ from collections.abc import Callable
18
+ from typing import Optional, Union
18
19
 
19
20
  import mlrun
20
21
  import mlrun.runtimes.kubejob as kubejob
mlrun/runtimes/mounts.py CHANGED
@@ -17,6 +17,8 @@ import typing
17
17
  import warnings
18
18
  from collections import namedtuple
19
19
 
20
+ import mlrun.common.secrets
21
+ import mlrun.errors
20
22
  from mlrun.config import config
21
23
  from mlrun.config import config as mlconf
22
24
  from mlrun.errors import MLRunInvalidArgumentError
@@ -412,6 +414,9 @@ def mount_secret(
412
414
  the specified paths, and unlisted keys will not be
413
415
  present."""
414
416
 
417
+ if secret_name:
418
+ mlrun.common.secrets.validate_not_forbidden_secret(secret_name.strip())
419
+
415
420
  def _mount_secret(runtime: "KubeResource"):
416
421
  # Define the secret volume source
417
422
  secret_volume_source = {
@@ -12,11 +12,15 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from .serving import ServingRuntime, new_v2_model_server # noqa
16
- from .nuclio import nuclio_init_hook # noqa
17
- from .function import (
18
- min_nuclio_versions,
19
- multiple_port_sidecar_is_supported,
20
- RemoteRuntime,
21
- ) # noqa
22
- from .api_gateway import APIGateway
15
+ import mlrun.runtimes.nuclio.serving as nuclio_serving # noqa
16
+ import mlrun.runtimes.nuclio.nuclio as nuclio_nuclio # noqa
17
+ import mlrun.runtimes.nuclio.function as nuclio_function # noqa
18
+ import mlrun.runtimes.nuclio.api_gateway as nuclio_api_gateway # noqa
19
+
20
+ ServingRuntime = nuclio_serving.ServingRuntime
21
+ new_v2_model_server = nuclio_serving.new_v2_model_server
22
+ nuclio_init_hook = nuclio_nuclio.nuclio_init_hook
23
+ min_nuclio_versions = nuclio_function.min_nuclio_versions
24
+ multiple_port_sidecar_is_supported = nuclio_function.multiple_port_sidecar_is_supported
25
+ RemoteRuntime = nuclio_function.RemoteRuntime
26
+ APIGateway = nuclio_api_gateway.APIGateway
@@ -17,13 +17,14 @@ from typing import Optional, Union
17
17
  from urllib.parse import urljoin
18
18
 
19
19
  import requests
20
- from nuclio.auth import AuthInfo as NuclioAuthInfo
21
20
  from nuclio.auth import AuthKinds as NuclioAuthKinds
22
21
 
23
22
  import mlrun
23
+ import mlrun.auth.nuclio
24
24
  import mlrun.common.constants as mlrun_constants
25
25
  import mlrun.common.helpers
26
26
  import mlrun.common.schemas as schemas
27
+ import mlrun.common.schemas.auth
27
28
  import mlrun.common.types
28
29
  from mlrun.model import ModelObj
29
30
  from mlrun.platforms.iguazio import min_iguazio_versions
@@ -55,6 +56,11 @@ class Authenticator(typing.Protocol):
55
56
  == schemas.APIGatewayAuthenticationMode.access_key.value
56
57
  ):
57
58
  return AccessKeyAuth()
59
+ elif (
60
+ api_gateway_spec.authenticationMode
61
+ == schemas.APIGatewayAuthenticationMode.iguazio.value
62
+ ):
63
+ return IguazioAuth()
58
64
  else:
59
65
  return NoneAuth()
60
66
 
@@ -112,6 +118,16 @@ class AccessKeyAuth(APIGatewayAuthenticator):
112
118
  return schemas.APIGatewayAuthenticationMode.access_key.value
113
119
 
114
120
 
121
+ class IguazioAuth(APIGatewayAuthenticator):
122
+ """
123
+ An API gateway authenticator with Iguazio authentication.
124
+ """
125
+
126
+ @property
127
+ def authentication_mode(self) -> str:
128
+ return schemas.APIGatewayAuthenticationMode.iguazio.value
129
+
130
+
115
131
  class APIGatewayMetadata(ModelObj):
116
132
  _dict_fields = ["name", "namespace", "labels", "annotations", "creation_timestamp"]
117
133
 
@@ -430,7 +446,7 @@ class APIGateway(ModelObj):
430
446
  raise mlrun.errors.MLRunInvalidArgumentError(
431
447
  "API Gateway invocation requires authentication. Please pass credentials"
432
448
  )
433
- auth = NuclioAuthInfo(
449
+ auth = mlrun.auth.nuclio.NuclioAuthInfo(
434
450
  username=credentials[0], password=credentials[1]
435
451
  ).to_requests_auth()
436
452
 
@@ -440,23 +456,30 @@ class APIGateway(ModelObj):
440
456
  ):
441
457
  # inject access key from env
442
458
  if credentials:
443
- auth = NuclioAuthInfo(
459
+ auth = mlrun.auth.nuclio.NuclioAuthInfo(
444
460
  username=credentials[0],
445
461
  password=credentials[1],
446
462
  mode=NuclioAuthKinds.iguazio,
447
463
  ).to_requests_auth()
448
464
  else:
449
- auth = NuclioAuthInfo().from_envvar().to_requests_auth()
465
+ auth = (
466
+ mlrun.auth.nuclio.NuclioAuthInfo().from_envvar().to_requests_auth()
467
+ )
450
468
  if not auth:
451
469
  raise mlrun.errors.MLRunInvalidArgumentError(
452
470
  "API Gateway invocation requires authentication. Please set V3IO_ACCESS_KEY env var"
453
471
  )
472
+ if (
473
+ self.spec.authentication.authentication_mode
474
+ == schemas.APIGatewayAuthenticationMode.iguazio.value
475
+ ):
476
+ auth = mlrun.auth.nuclio.NuclioAuthInfo.from_envvar().to_requests_auth()
454
477
  url = urljoin(self.invoke_url, path or "")
455
478
 
456
479
  # Determine the correct keyword argument for the body
457
480
  if isinstance(body, dict):
458
481
  kwargs["json"] = body
459
- elif isinstance(body, (str, bytes)):
482
+ elif isinstance(body, str | bytes):
460
483
  kwargs["data"] = body
461
484
 
462
485
  return requests.request(
@@ -527,6 +550,13 @@ class APIGateway(ModelObj):
527
550
  """
528
551
  self.spec.authentication = AccessKeyAuth()
529
552
 
553
+ @min_nuclio_versions("1.15.10")
554
+ def with_iguazio_auth(self):
555
+ """
556
+ Set iguazio authentication for the API gateway.
557
+ """
558
+ self.spec.authentication = IguazioAuth()
559
+
530
560
  def with_canary(
531
561
  self,
532
562
  functions: Union[
@@ -692,7 +722,7 @@ class APIGateway(ModelObj):
692
722
  @staticmethod
693
723
  def _generate_basic_auth(username: str, password: str):
694
724
  token = base64.b64encode(f"{username}:{password}".encode()).decode()
695
- return f"Basic {token}"
725
+ return f"{mlrun.common.schemas.AuthorizationHeaderPrefixes.basic}{token}"
696
726
 
697
727
  @staticmethod
698
728
  def _resolve_canary(