mlrun 1.7.0rc14__py3-none-any.whl → 1.7.0rc22__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 (160) hide show
  1. mlrun/__init__.py +10 -1
  2. mlrun/__main__.py +23 -111
  3. mlrun/alerts/__init__.py +15 -0
  4. mlrun/alerts/alert.py +169 -0
  5. mlrun/api/schemas/__init__.py +4 -3
  6. mlrun/artifacts/__init__.py +8 -3
  7. mlrun/artifacts/base.py +36 -253
  8. mlrun/artifacts/dataset.py +9 -190
  9. mlrun/artifacts/manager.py +46 -42
  10. mlrun/artifacts/model.py +9 -141
  11. mlrun/artifacts/plots.py +14 -375
  12. mlrun/common/constants.py +65 -3
  13. mlrun/common/formatters/__init__.py +19 -0
  14. mlrun/{runtimes/mpijob/v1alpha1.py → common/formatters/artifact.py} +6 -14
  15. mlrun/common/formatters/base.py +113 -0
  16. mlrun/common/formatters/function.py +46 -0
  17. mlrun/common/formatters/pipeline.py +53 -0
  18. mlrun/common/formatters/project.py +51 -0
  19. mlrun/{runtimes → common/runtimes}/constants.py +32 -4
  20. mlrun/common/schemas/__init__.py +10 -5
  21. mlrun/common/schemas/alert.py +92 -11
  22. mlrun/common/schemas/api_gateway.py +56 -0
  23. mlrun/common/schemas/artifact.py +15 -5
  24. mlrun/common/schemas/auth.py +2 -0
  25. mlrun/common/schemas/client_spec.py +1 -0
  26. mlrun/common/schemas/frontend_spec.py +1 -0
  27. mlrun/common/schemas/function.py +4 -0
  28. mlrun/common/schemas/model_monitoring/__init__.py +15 -3
  29. mlrun/common/schemas/model_monitoring/constants.py +58 -7
  30. mlrun/common/schemas/model_monitoring/grafana.py +9 -5
  31. mlrun/common/schemas/model_monitoring/model_endpoints.py +86 -2
  32. mlrun/common/schemas/pipeline.py +0 -9
  33. mlrun/common/schemas/project.py +5 -11
  34. mlrun/common/types.py +1 -0
  35. mlrun/config.py +30 -9
  36. mlrun/data_types/to_pandas.py +9 -9
  37. mlrun/datastore/base.py +41 -9
  38. mlrun/datastore/datastore.py +6 -2
  39. mlrun/datastore/datastore_profile.py +56 -4
  40. mlrun/datastore/inmem.py +2 -2
  41. mlrun/datastore/redis.py +2 -2
  42. mlrun/datastore/s3.py +5 -0
  43. mlrun/datastore/sources.py +147 -7
  44. mlrun/datastore/store_resources.py +7 -7
  45. mlrun/datastore/targets.py +110 -42
  46. mlrun/datastore/utils.py +42 -0
  47. mlrun/db/base.py +54 -10
  48. mlrun/db/httpdb.py +282 -79
  49. mlrun/db/nopdb.py +52 -10
  50. mlrun/errors.py +11 -0
  51. mlrun/execution.py +26 -9
  52. mlrun/feature_store/__init__.py +0 -2
  53. mlrun/feature_store/api.py +12 -47
  54. mlrun/feature_store/feature_set.py +9 -0
  55. mlrun/feature_store/feature_vector.py +8 -0
  56. mlrun/feature_store/ingestion.py +7 -6
  57. mlrun/feature_store/retrieval/base.py +9 -4
  58. mlrun/feature_store/retrieval/conversion.py +9 -9
  59. mlrun/feature_store/retrieval/dask_merger.py +2 -0
  60. mlrun/feature_store/retrieval/job.py +9 -3
  61. mlrun/feature_store/retrieval/local_merger.py +2 -0
  62. mlrun/feature_store/retrieval/spark_merger.py +16 -0
  63. mlrun/frameworks/__init__.py +6 -0
  64. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
  65. mlrun/frameworks/parallel_coordinates.py +2 -1
  66. mlrun/frameworks/tf_keras/__init__.py +4 -1
  67. mlrun/k8s_utils.py +10 -11
  68. mlrun/launcher/base.py +4 -3
  69. mlrun/launcher/client.py +5 -3
  70. mlrun/launcher/local.py +12 -2
  71. mlrun/launcher/remote.py +9 -2
  72. mlrun/lists.py +6 -2
  73. mlrun/model.py +47 -21
  74. mlrun/model_monitoring/__init__.py +1 -1
  75. mlrun/model_monitoring/api.py +42 -18
  76. mlrun/model_monitoring/application.py +5 -305
  77. mlrun/model_monitoring/applications/__init__.py +11 -0
  78. mlrun/model_monitoring/applications/_application_steps.py +157 -0
  79. mlrun/model_monitoring/applications/base.py +280 -0
  80. mlrun/model_monitoring/applications/context.py +214 -0
  81. mlrun/model_monitoring/applications/evidently_base.py +211 -0
  82. mlrun/model_monitoring/applications/histogram_data_drift.py +132 -91
  83. mlrun/model_monitoring/applications/results.py +99 -0
  84. mlrun/model_monitoring/controller.py +3 -1
  85. mlrun/model_monitoring/db/__init__.py +2 -0
  86. mlrun/model_monitoring/db/stores/__init__.py +0 -2
  87. mlrun/model_monitoring/db/stores/base/store.py +22 -37
  88. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +43 -21
  89. mlrun/model_monitoring/db/stores/sqldb/models/base.py +39 -8
  90. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +27 -7
  91. mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +5 -0
  92. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +246 -224
  93. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +232 -216
  94. mlrun/model_monitoring/db/tsdb/__init__.py +100 -0
  95. mlrun/model_monitoring/db/tsdb/base.py +316 -0
  96. mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
  97. mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
  98. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +240 -0
  99. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +45 -0
  100. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +401 -0
  101. mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
  102. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
  103. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +658 -0
  104. mlrun/model_monitoring/evidently_application.py +6 -118
  105. mlrun/model_monitoring/helpers.py +63 -1
  106. mlrun/model_monitoring/model_endpoint.py +3 -2
  107. mlrun/model_monitoring/stream_processing.py +57 -216
  108. mlrun/model_monitoring/writer.py +134 -124
  109. mlrun/package/__init__.py +13 -1
  110. mlrun/package/packagers/__init__.py +6 -1
  111. mlrun/package/utils/_formatter.py +2 -2
  112. mlrun/platforms/__init__.py +10 -9
  113. mlrun/platforms/iguazio.py +21 -202
  114. mlrun/projects/operations.py +24 -12
  115. mlrun/projects/pipelines.py +79 -102
  116. mlrun/projects/project.py +271 -103
  117. mlrun/render.py +15 -14
  118. mlrun/run.py +16 -46
  119. mlrun/runtimes/__init__.py +6 -3
  120. mlrun/runtimes/base.py +14 -7
  121. mlrun/runtimes/daskjob.py +1 -0
  122. mlrun/runtimes/databricks_job/databricks_runtime.py +1 -0
  123. mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
  124. mlrun/runtimes/funcdoc.py +0 -28
  125. mlrun/runtimes/kubejob.py +2 -1
  126. mlrun/runtimes/local.py +12 -3
  127. mlrun/runtimes/mpijob/__init__.py +0 -20
  128. mlrun/runtimes/mpijob/v1.py +1 -1
  129. mlrun/runtimes/nuclio/api_gateway.py +194 -84
  130. mlrun/runtimes/nuclio/application/application.py +170 -8
  131. mlrun/runtimes/nuclio/function.py +39 -49
  132. mlrun/runtimes/pod.py +16 -36
  133. mlrun/runtimes/remotesparkjob.py +9 -3
  134. mlrun/runtimes/sparkjob/spark3job.py +1 -1
  135. mlrun/runtimes/utils.py +6 -45
  136. mlrun/serving/__init__.py +8 -1
  137. mlrun/serving/server.py +2 -1
  138. mlrun/serving/states.py +51 -8
  139. mlrun/serving/utils.py +19 -11
  140. mlrun/serving/v2_serving.py +5 -1
  141. mlrun/track/tracker.py +2 -1
  142. mlrun/utils/async_http.py +25 -5
  143. mlrun/utils/helpers.py +157 -83
  144. mlrun/utils/logger.py +39 -7
  145. mlrun/utils/notifications/notification/__init__.py +14 -9
  146. mlrun/utils/notifications/notification/base.py +1 -1
  147. mlrun/utils/notifications/notification/slack.py +34 -7
  148. mlrun/utils/notifications/notification/webhook.py +1 -1
  149. mlrun/utils/notifications/notification_pusher.py +147 -16
  150. mlrun/utils/regex.py +9 -0
  151. mlrun/utils/v3io_clients.py +0 -1
  152. mlrun/utils/version/version.json +2 -2
  153. {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/METADATA +14 -6
  154. {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/RECORD +158 -138
  155. mlrun/kfpops.py +0 -865
  156. mlrun/platforms/other.py +0 -305
  157. {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/LICENSE +0 -0
  158. {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/WHEEL +0 -0
  159. {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/entry_points.txt +0 -0
  160. {mlrun-1.7.0rc14.dist-info → mlrun-1.7.0rc22.dist-info}/top_level.txt +0 -0
@@ -12,14 +12,22 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  import pathlib
15
+ import typing
15
16
 
16
17
  import nuclio
17
18
 
19
+ import mlrun.common.schemas as schemas
18
20
  import mlrun.errors
19
- from mlrun.common.schemas import AuthInfo
21
+ from mlrun.common.runtimes.constants import NuclioIngressAddTemplatedIngressModes
20
22
  from mlrun.runtimes import RemoteRuntime
21
23
  from mlrun.runtimes.nuclio import min_nuclio_versions
24
+ from mlrun.runtimes.nuclio.api_gateway import (
25
+ APIGateway,
26
+ APIGatewayMetadata,
27
+ APIGatewaySpec,
28
+ )
22
29
  from mlrun.runtimes.nuclio.function import NuclioSpec, NuclioStatus
30
+ from mlrun.utils import logger
23
31
 
24
32
 
25
33
  class ApplicationSpec(NuclioSpec):
@@ -113,7 +121,10 @@ class ApplicationSpec(NuclioSpec):
113
121
  state_thresholds=state_thresholds,
114
122
  disable_default_http_trigger=disable_default_http_trigger,
115
123
  )
116
- self.internal_application_port = internal_application_port or 8080
124
+ self.internal_application_port = (
125
+ internal_application_port
126
+ or mlrun.mlconf.function.application.default_sidecar_internal_port
127
+ )
117
128
 
118
129
  @property
119
130
  def internal_application_port(self):
@@ -139,6 +150,9 @@ class ApplicationStatus(NuclioStatus):
139
150
  container_image=None,
140
151
  application_image=None,
141
152
  sidecar_name=None,
153
+ api_gateway_name=None,
154
+ api_gateway=None,
155
+ url=None,
142
156
  ):
143
157
  super().__init__(
144
158
  state=state,
@@ -151,12 +165,15 @@ class ApplicationStatus(NuclioStatus):
151
165
  )
152
166
  self.application_image = application_image or None
153
167
  self.sidecar_name = sidecar_name or None
168
+ self.api_gateway_name = api_gateway_name or None
169
+ self.api_gateway = api_gateway or None
170
+ self.url = url or None
154
171
 
155
172
 
156
173
  class ApplicationRuntime(RemoteRuntime):
157
174
  kind = "application"
158
175
 
159
- @min_nuclio_versions("1.12.7")
176
+ @min_nuclio_versions("1.13.1")
160
177
  def __init__(self, spec=None, metadata=None):
161
178
  super().__init__(spec=spec, metadata=metadata)
162
179
 
@@ -176,6 +193,24 @@ class ApplicationRuntime(RemoteRuntime):
176
193
  def status(self, status):
177
194
  self._status = self._verify_dict(status, "status", ApplicationStatus)
178
195
 
196
+ @property
197
+ def api_gateway(self):
198
+ return self.status.api_gateway
199
+
200
+ @api_gateway.setter
201
+ def api_gateway(self, api_gateway: APIGateway):
202
+ self.status.api_gateway = api_gateway
203
+
204
+ @property
205
+ def url(self):
206
+ if not self.status.api_gateway:
207
+ self._sync_api_gateway()
208
+ return self.status.api_gateway.invoke_url
209
+
210
+ @url.setter
211
+ def url(self, url):
212
+ self.status.url = url
213
+
179
214
  def set_internal_application_port(self, port: int):
180
215
  self.spec.internal_application_port = port
181
216
 
@@ -220,7 +255,7 @@ class ApplicationRuntime(RemoteRuntime):
220
255
  project="",
221
256
  tag="",
222
257
  verbose=False,
223
- auth_info: AuthInfo = None,
258
+ auth_info: schemas.AuthInfo = None,
224
259
  builder_env: dict = None,
225
260
  force_build: bool = False,
226
261
  with_mlrun=None,
@@ -228,6 +263,10 @@ class ApplicationRuntime(RemoteRuntime):
228
263
  is_kfp=False,
229
264
  mlrun_version_specifier=None,
230
265
  show_on_failure: bool = False,
266
+ skip_access_key_auth: bool = False,
267
+ direct_port_access: bool = False,
268
+ authentication_mode: schemas.APIGatewayAuthenticationMode = None,
269
+ authentication_creds: tuple[str] = None,
231
270
  ):
232
271
  """
233
272
  Deploy function, builds the application image if required (self.requires_build()) or force_build is True,
@@ -244,6 +283,10 @@ class ApplicationRuntime(RemoteRuntime):
244
283
  :param is_kfp: Deploy as part of a kfp pipeline
245
284
  :param mlrun_version_specifier: Which mlrun package version to include (if not current)
246
285
  :param show_on_failure: Show logs only in case of build failure
286
+ :param skip_access_key_auth: Skip adding access key auth to the API Gateway
287
+ :param direct_port_access: Set True to allow direct port access to the application sidecar
288
+ :param authentication_mode: API Gateway authentication mode
289
+ :param authentication_creds: API Gateway authentication credentials as a tuple (username, password)
247
290
  :return: True if the function is ready (deployed)
248
291
  """
249
292
  if self.requires_build() or force_build:
@@ -261,6 +304,16 @@ class ApplicationRuntime(RemoteRuntime):
261
304
 
262
305
  self._ensure_reverse_proxy_configurations()
263
306
  self._configure_application_sidecar()
307
+
308
+ # we only allow accessing the application via the API Gateway
309
+ name_tag = tag or self.metadata.tag
310
+ self.status.api_gateway_name = (
311
+ f"{self.metadata.name}-{name_tag}" if name_tag else self.metadata.name
312
+ )
313
+ self.spec.add_templated_ingress_host_mode = (
314
+ NuclioIngressAddTemplatedIngressModes.never
315
+ )
316
+
264
317
  super().deploy(
265
318
  project,
266
319
  tag,
@@ -269,6 +322,14 @@ class ApplicationRuntime(RemoteRuntime):
269
322
  builder_env,
270
323
  )
271
324
 
325
+ ports = self.spec.internal_application_port if direct_port_access else []
326
+ self.create_api_gateway(
327
+ name=self.status.api_gateway_name,
328
+ ports=ports,
329
+ authentication_mode=authentication_mode,
330
+ authentication_creds=authentication_creds,
331
+ )
332
+
272
333
  def with_source_archive(
273
334
  self, source, workdir=None, pull_at_runtime=True, target_dir=None
274
335
  ):
@@ -290,6 +351,92 @@ class ApplicationRuntime(RemoteRuntime):
290
351
  target_dir=target_dir,
291
352
  )
292
353
 
354
+ @classmethod
355
+ def get_filename_and_handler(cls) -> (str, str):
356
+ reverse_proxy_file_path = pathlib.Path(__file__).parent / "reverse_proxy.go"
357
+ return str(reverse_proxy_file_path), "Handler"
358
+
359
+ def create_api_gateway(
360
+ self,
361
+ name: str = None,
362
+ path: str = None,
363
+ ports: list[int] = None,
364
+ authentication_mode: schemas.APIGatewayAuthenticationMode = None,
365
+ authentication_creds: tuple[str] = None,
366
+ ):
367
+ api_gateway = APIGateway(
368
+ APIGatewayMetadata(
369
+ name=name,
370
+ namespace=self.metadata.namespace,
371
+ labels=self.metadata.labels,
372
+ annotations=self.metadata.annotations,
373
+ ),
374
+ APIGatewaySpec(
375
+ functions=[self],
376
+ project=self.metadata.project,
377
+ path=path,
378
+ ports=mlrun.utils.helpers.as_list(ports) if ports else None,
379
+ ),
380
+ )
381
+
382
+ authentication_mode = (
383
+ authentication_mode
384
+ or mlrun.mlconf.function.application.default_authentication_mode
385
+ )
386
+ if authentication_mode == schemas.APIGatewayAuthenticationMode.access_key:
387
+ api_gateway.with_access_key_auth()
388
+ elif authentication_mode == schemas.APIGatewayAuthenticationMode.basic:
389
+ api_gateway.with_basic_auth(*authentication_creds)
390
+
391
+ db = self._get_db()
392
+ api_gateway_scheme = db.store_api_gateway(
393
+ api_gateway=api_gateway.to_scheme(), project=self.metadata.project
394
+ )
395
+ if not self.status.api_gateway_name:
396
+ self.status.api_gateway_name = api_gateway_scheme.metadata.name
397
+ self.status.api_gateway = APIGateway.from_scheme(api_gateway_scheme)
398
+ self.status.api_gateway.wait_for_readiness()
399
+ self.url = self.status.api_gateway.invoke_url
400
+
401
+ def invoke(
402
+ self,
403
+ path: str,
404
+ body: typing.Union[str, bytes, dict] = None,
405
+ method: str = None,
406
+ headers: dict = None,
407
+ dashboard: str = "",
408
+ force_external_address: bool = False,
409
+ auth_info: schemas.AuthInfo = None,
410
+ mock: bool = None,
411
+ **http_client_kwargs,
412
+ ):
413
+ self._sync_api_gateway()
414
+ # If the API Gateway is not ready or not set, try to invoke the function directly (without the API Gateway)
415
+ if not self.status.api_gateway:
416
+ super().invoke(
417
+ path,
418
+ body,
419
+ method,
420
+ headers,
421
+ dashboard,
422
+ force_external_address,
423
+ auth_info,
424
+ mock,
425
+ **http_client_kwargs,
426
+ )
427
+
428
+ credentials = (auth_info.username, auth_info.password) if auth_info else None
429
+
430
+ if not method:
431
+ method = "POST" if body else "GET"
432
+ return self.status.api_gateway.invoke(
433
+ method=method,
434
+ headers=headers,
435
+ credentials=credentials,
436
+ path=path,
437
+ **http_client_kwargs,
438
+ )
439
+
293
440
  def _build_application_image(
294
441
  self,
295
442
  builder_env: dict = None,
@@ -301,6 +448,14 @@ class ApplicationRuntime(RemoteRuntime):
301
448
  mlrun_version_specifier=None,
302
449
  show_on_failure: bool = False,
303
450
  ):
451
+ if not self.spec.command:
452
+ logger.warning(
453
+ "Building the application image without a command. "
454
+ "Use spec.command and spec.args to specify the application entrypoint",
455
+ command=self.spec.command,
456
+ args=self.spec.args,
457
+ )
458
+
304
459
  with_mlrun = self._resolve_build_with_mlrun(with_mlrun)
305
460
  return self._build_image(
306
461
  builder_env=builder_env,
@@ -355,7 +510,14 @@ class ApplicationRuntime(RemoteRuntime):
355
510
  self.set_env("SIDECAR_PORT", self.spec.internal_application_port)
356
511
  self.set_env("SIDECAR_HOST", "http://localhost")
357
512
 
358
- @classmethod
359
- def get_filename_and_handler(cls) -> (str, str):
360
- reverse_proxy_file_path = pathlib.Path(__file__).parent / "reverse_proxy.go"
361
- return str(reverse_proxy_file_path), "Handler"
513
+ def _sync_api_gateway(self):
514
+ if not self.status.api_gateway_name:
515
+ return
516
+
517
+ db = self._get_db()
518
+ api_gateway_scheme = db.get_api_gateway(
519
+ name=self.status.api_gateway_name, project=self.metadata.project
520
+ )
521
+ self.status.api_gateway = APIGateway.from_scheme(api_gateway_scheme)
522
+ self.status.api_gateway.wait_for_readiness()
523
+ self.url = self.status.api_gateway.invoke_url
@@ -19,12 +19,15 @@ import warnings
19
19
  from datetime import datetime
20
20
  from time import sleep
21
21
 
22
+ import inflection
22
23
  import nuclio
23
24
  import nuclio.utils
24
25
  import requests
25
- import semver
26
26
  from aiohttp.client import ClientSession
27
27
  from kubernetes import client
28
+ from mlrun_pipelines.common.mounts import VolumeMount
29
+ from mlrun_pipelines.common.ops import deploy_op
30
+ from mlrun_pipelines.mounts import mount_v3io, v3io_cred
28
31
  from nuclio.deploy import find_dashboard_url, get_deploy_status
29
32
  from nuclio.triggers import V3IOStreamTrigger
30
33
 
@@ -36,15 +39,11 @@ import mlrun.utils.helpers
36
39
  from mlrun.common.schemas import AuthInfo
37
40
  from mlrun.config import config as mlconf
38
41
  from mlrun.errors import err_to_str
39
- from mlrun.kfpops import deploy_op
40
42
  from mlrun.lists import RunList
41
43
  from mlrun.model import RunObject
42
44
  from mlrun.platforms.iguazio import (
43
- VolumeMount,
44
- mount_v3io,
45
45
  parse_path,
46
46
  split_path,
47
- v3io_cred,
48
47
  )
49
48
  from mlrun.runtimes.base import FunctionStatus, RunError
50
49
  from mlrun.runtimes.pod import KubeResource, KubeResourceSpec
@@ -56,33 +55,9 @@ def validate_nuclio_version_compatibility(*min_versions):
56
55
  """
57
56
  :param min_versions: Valid minimum version(s) required, assuming no 2 versions has equal major and minor.
58
57
  """
59
- parsed_min_versions = [
60
- semver.VersionInfo.parse(min_version) for min_version in min_versions
61
- ]
62
- try:
63
- parsed_current_version = semver.VersionInfo.parse(mlconf.nuclio_version)
64
- except ValueError:
65
- # only log when version is set but invalid
66
- if mlconf.nuclio_version:
67
- logger.warning(
68
- "Unable to parse nuclio version, assuming compatibility",
69
- nuclio_version=mlconf.nuclio_version,
70
- min_versions=min_versions,
71
- )
72
- return True
73
-
74
- parsed_min_versions.sort(reverse=True)
75
- for parsed_min_version in parsed_min_versions:
76
- if (
77
- parsed_current_version.major == parsed_min_version.major
78
- and parsed_current_version.minor == parsed_min_version.minor
79
- and parsed_current_version.patch < parsed_min_version.patch
80
- ):
81
- return False
82
-
83
- if parsed_current_version >= parsed_min_version:
84
- return True
85
- return False
58
+ return mlrun.utils.helpers.validate_component_version_compatibility(
59
+ "nuclio", *min_versions
60
+ )
86
61
 
87
62
 
88
63
  def min_nuclio_versions(*versions):
@@ -91,9 +66,13 @@ def min_nuclio_versions(*versions):
91
66
  if validate_nuclio_version_compatibility(*versions):
92
67
  return function(*args, **kwargs)
93
68
 
69
+ if function.__name__ == "__init__":
70
+ name = inflection.titleize(function.__qualname__.split(".")[0])
71
+ else:
72
+ name = function.__qualname__
73
+
94
74
  message = (
95
- f"{function.__name__} is supported since nuclio {' or '.join(versions)}, currently using "
96
- f"nuclio {mlconf.nuclio_version}, please upgrade."
75
+ f"'{name}' function requires Nuclio v{' or v'.join(versions)} or higher"
97
76
  )
98
77
  raise mlrun.errors.MLRunIncompatibleVersionError(message)
99
78
 
@@ -292,7 +271,8 @@ class RemoteRuntime(KubeResource):
292
271
  self._status = self._verify_dict(status, "status", NuclioStatus)
293
272
 
294
273
  def pre_deploy_validation(self):
295
- pass
274
+ if self.metadata.tag:
275
+ mlrun.utils.validate_tag_name(self.metadata.tag, "function.metadata.tag")
296
276
 
297
277
  def set_config(self, key, value):
298
278
  self.spec.config[key] = value
@@ -573,7 +553,6 @@ class RemoteRuntime(KubeResource):
573
553
  if tag:
574
554
  self.metadata.tag = tag
575
555
 
576
- save_record = False
577
556
  # Attempt auto-mounting, before sending to remote build
578
557
  self.try_auto_mount_based_on_config()
579
558
  self._fill_credentials()
@@ -591,15 +570,18 @@ class RemoteRuntime(KubeResource):
591
570
  # now, functions can be not exposed (using service type ClusterIP) and hence
592
571
  # for BC we first try to populate the external invocation url, and then
593
572
  # if not exists, take the internal invocation url
594
- if self.status.external_invocation_urls:
573
+ if (
574
+ self.status.external_invocation_urls
575
+ and self.status.external_invocation_urls[0] != ""
576
+ ):
595
577
  self.spec.command = f"http://{self.status.external_invocation_urls[0]}"
596
- save_record = True
597
- elif self.status.internal_invocation_urls:
578
+ elif (
579
+ self.status.internal_invocation_urls
580
+ and self.status.internal_invocation_urls[0] != ""
581
+ ):
598
582
  self.spec.command = f"http://{self.status.internal_invocation_urls[0]}"
599
- save_record = True
600
- elif self.status.address:
583
+ elif self.status.address and self.status.address != "":
601
584
  self.spec.command = f"http://{self.status.address}"
602
- save_record = True
603
585
 
604
586
  logger.info(
605
587
  "Successfully deployed function",
@@ -607,8 +589,7 @@ class RemoteRuntime(KubeResource):
607
589
  external_invocation_urls=self.status.external_invocation_urls,
608
590
  )
609
591
 
610
- if save_record:
611
- self.save(versioned=False)
592
+ self.save(versioned=False)
612
593
 
613
594
  return self.spec.command
614
595
 
@@ -778,7 +759,7 @@ class RemoteRuntime(KubeResource):
778
759
  runtime_env["MLRUN_NAMESPACE"] = mlconf.namespace
779
760
  if self.metadata.credentials.access_key:
780
761
  runtime_env[
781
- mlrun.runtimes.constants.FunctionEnvironmentVariables.auth_session
762
+ mlrun.common.runtimes.constants.FunctionEnvironmentVariables.auth_session
782
763
  ] = self.metadata.credentials.access_key
783
764
  return runtime_env
784
765
 
@@ -992,21 +973,30 @@ class RemoteRuntime(KubeResource):
992
973
  sidecar["image"] = image
993
974
 
994
975
  ports = mlrun.utils.helpers.as_list(ports)
976
+ # according to RFC-6335, port name should be less than 15 characters,
977
+ # so we truncate it if needed and leave room for the index
978
+ port_name = name[:13].rstrip("-_") if len(name) > 13 else name
995
979
  sidecar["ports"] = [
996
980
  {
997
- "name": "http",
981
+ "name": f"{port_name}-{i}",
998
982
  "containerPort": port,
999
983
  "protocol": "TCP",
1000
984
  }
1001
- for port in ports
985
+ for i, port in enumerate(ports)
1002
986
  ]
1003
987
 
1004
- if command:
988
+ # if it is a redeploy, 'command' might be set with the previous invocation url.
989
+ # in this case, we don't want to use it as the sidecar command
990
+ if command and not command.startswith("http"):
1005
991
  sidecar["command"] = mlrun.utils.helpers.as_list(command)
1006
992
 
1007
- if args:
993
+ if args and sidecar["command"]:
1008
994
  sidecar["args"] = mlrun.utils.helpers.as_list(args)
1009
995
 
996
+ # populate the sidecar resources from the function spec
997
+ if self.spec.resources:
998
+ sidecar["resources"] = self.spec.resources
999
+
1010
1000
  def _set_sidecar(self, name: str) -> dict:
1011
1001
  self.spec.config.setdefault("spec.sidecars", [])
1012
1002
  sidecars = self.spec.config["spec.sidecars"]
mlrun/runtimes/pod.py CHANGED
@@ -20,8 +20,9 @@ import typing
20
20
  from enum import Enum
21
21
 
22
22
  import dotenv
23
- import kfp.dsl
24
23
  import kubernetes.client as k8s_client
24
+ import mlrun_pipelines.mounts
25
+ from mlrun_pipelines.mixins import KfpAdapterMixin
25
26
 
26
27
  import mlrun.errors
27
28
  import mlrun.utils.regex
@@ -41,7 +42,6 @@ from ..k8s_utils import (
41
42
  from ..utils import logger, update_in
42
43
  from .base import BaseRuntime, FunctionSpec, spec_fields
43
44
  from .utils import (
44
- apply_kfp,
45
45
  get_gpu_from_resource_requirement,
46
46
  get_item_name,
47
47
  set_named_item,
@@ -935,12 +935,12 @@ class AutoMountType(str, Enum):
935
935
  @classmethod
936
936
  def all_mount_modifiers(cls):
937
937
  return [
938
- mlrun.v3io_cred.__name__,
939
- mlrun.mount_v3io.__name__,
940
- mlrun.platforms.other.mount_pvc.__name__,
941
- mlrun.auto_mount.__name__,
942
- mlrun.platforms.mount_s3.__name__,
943
- mlrun.platforms.set_env_variables.__name__,
938
+ mlrun_pipelines.mounts.v3io_cred.__name__,
939
+ mlrun_pipelines.mounts.mount_v3io.__name__,
940
+ mlrun_pipelines.mounts.mount_pvc.__name__,
941
+ mlrun_pipelines.mounts.auto_mount.__name__,
942
+ mlrun_pipelines.mounts.mount_s3.__name__,
943
+ mlrun_pipelines.mounts.set_env_variables.__name__,
944
944
  ]
945
945
 
946
946
  @classmethod
@@ -957,27 +957,27 @@ class AutoMountType(str, Enum):
957
957
  def _get_auto_modifier():
958
958
  # If we're running on Iguazio - use v3io_cred
959
959
  if mlconf.igz_version != "":
960
- return mlrun.v3io_cred
960
+ return mlrun_pipelines.mounts.v3io_cred
961
961
  # Else, either pvc mount if it's configured or do nothing otherwise
962
962
  pvc_configured = (
963
963
  "MLRUN_PVC_MOUNT" in os.environ
964
964
  or "pvc_name" in mlconf.get_storage_auto_mount_params()
965
965
  )
966
- return mlrun.platforms.other.mount_pvc if pvc_configured else None
966
+ return mlrun_pipelines.mounts.mount_pvc if pvc_configured else None
967
967
 
968
968
  def get_modifier(self):
969
969
  return {
970
970
  AutoMountType.none: None,
971
- AutoMountType.v3io_credentials: mlrun.v3io_cred,
972
- AutoMountType.v3io_fuse: mlrun.mount_v3io,
973
- AutoMountType.pvc: mlrun.platforms.other.mount_pvc,
971
+ AutoMountType.v3io_credentials: mlrun_pipelines.mounts.v3io_cred,
972
+ AutoMountType.v3io_fuse: mlrun_pipelines.mounts.mount_v3io,
973
+ AutoMountType.pvc: mlrun_pipelines.mounts.mount_pvc,
974
974
  AutoMountType.auto: self._get_auto_modifier(),
975
- AutoMountType.s3: mlrun.platforms.mount_s3,
976
- AutoMountType.env: mlrun.platforms.set_env_variables,
975
+ AutoMountType.s3: mlrun_pipelines.mounts.mount_s3,
976
+ AutoMountType.env: mlrun_pipelines.mounts.set_env_variables,
977
977
  }[self]
978
978
 
979
979
 
980
- class KubeResource(BaseRuntime):
980
+ class KubeResource(BaseRuntime, KfpAdapterMixin):
981
981
  """
982
982
  A parent class for runtimes that generate k8s resources when executing.
983
983
  """
@@ -997,26 +997,6 @@ class KubeResource(BaseRuntime):
997
997
  def spec(self, spec):
998
998
  self._spec = self._verify_dict(spec, "spec", KubeResourceSpec)
999
999
 
1000
- def apply(self, modify):
1001
- """
1002
- Apply a modifier to the runtime which is used to change the runtimes k8s object's spec.
1003
- Modifiers can be either KFP modifiers or MLRun modifiers (which are compatible with KFP). All modifiers accept
1004
- a `kfp.dsl.ContainerOp` object, apply some changes on its spec and return it so modifiers can be chained
1005
- one after the other.
1006
-
1007
- :param modify: a modifier runnable object
1008
- :return: the runtime (self) after the modifications
1009
- """
1010
-
1011
- # Kubeflow pipeline have a hook to add the component to the DAG on ContainerOp init
1012
- # we remove the hook to suppress kubeflow op registration and return it after the apply()
1013
- old_op_handler = kfp.dsl._container_op._register_op_handler
1014
- kfp.dsl._container_op._register_op_handler = lambda x: self.metadata.name
1015
- cop = kfp.dsl.ContainerOp("name", "image")
1016
- kfp.dsl._container_op._register_op_handler = old_op_handler
1017
-
1018
- return apply_kfp(modify, cop, self)
1019
-
1020
1000
  def set_env_from_secret(self, name, secret=None, secret_key=None):
1021
1001
  """set pod environment var from secret"""
1022
1002
  secret_key = secret_key or name
@@ -15,11 +15,11 @@ import re
15
15
  from subprocess import run
16
16
 
17
17
  import kubernetes.client
18
+ from mlrun_pipelines.mounts import mount_v3io, mount_v3iod
18
19
 
19
20
  import mlrun.errors
20
21
  from mlrun.config import config
21
22
 
22
- from ..platforms.iguazio import mount_v3io, mount_v3iod
23
23
  from .kubejob import KubejobRuntime
24
24
  from .pod import KubeResourceSpec
25
25
 
@@ -130,14 +130,20 @@ class RemoteSparkRuntime(KubejobRuntime):
130
130
  def spec(self, spec):
131
131
  self._spec = self._verify_dict(spec, "spec", RemoteSparkSpec)
132
132
 
133
- def with_spark_service(self, spark_service, provider=RemoteSparkProviders.iguazio):
133
+ def with_spark_service(
134
+ self,
135
+ spark_service,
136
+ provider=RemoteSparkProviders.iguazio,
137
+ with_v3io_mount=True,
138
+ ):
134
139
  """Attach spark service to function"""
135
140
  self.spec.provider = provider
136
141
  if provider == RemoteSparkProviders.iguazio:
137
142
  self.spec.env.append(
138
143
  {"name": "MLRUN_SPARK_CLIENT_IGZ_SPARK", "value": "true"}
139
144
  )
140
- self.apply(mount_v3io())
145
+ if with_v3io_mount:
146
+ self.apply(mount_v3io())
141
147
  self.apply(
142
148
  mount_v3iod(
143
149
  namespace=config.namespace,
@@ -14,6 +14,7 @@
14
14
  import typing
15
15
 
16
16
  import kubernetes.client
17
+ from mlrun_pipelines.mounts import mount_v3io, mount_v3iod
17
18
 
18
19
  import mlrun.common.schemas.function
19
20
  import mlrun.errors
@@ -22,7 +23,6 @@ from mlrun.config import config
22
23
 
23
24
  from ...execution import MLClientCtx
24
25
  from ...model import RunObject
25
- from ...platforms.iguazio import mount_v3io, mount_v3iod
26
26
  from ...utils import update_in, verify_field_regex
27
27
  from ..kubejob import KubejobRuntime
28
28
  from ..pod import KubeResourceSpec