mlrun 1.5.0rc12__py3-none-any.whl → 1.5.0rc13__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 (45) hide show
  1. mlrun/__main__.py +31 -2
  2. mlrun/api/api/endpoints/functions.py +110 -52
  3. mlrun/api/crud/model_monitoring/deployment.py +208 -38
  4. mlrun/api/crud/model_monitoring/helpers.py +19 -6
  5. mlrun/api/crud/model_monitoring/model_endpoints.py +14 -1
  6. mlrun/api/db/sqldb/db.py +3 -1
  7. mlrun/api/utils/builder.py +2 -4
  8. mlrun/common/model_monitoring/helpers.py +19 -5
  9. mlrun/common/schemas/model_monitoring/constants.py +69 -0
  10. mlrun/common/schemas/model_monitoring/model_endpoints.py +10 -0
  11. mlrun/config.py +30 -12
  12. mlrun/datastore/__init__.py +1 -0
  13. mlrun/datastore/sources.py +4 -30
  14. mlrun/datastore/targets.py +68 -31
  15. mlrun/db/httpdb.py +20 -6
  16. mlrun/feature_store/api.py +3 -31
  17. mlrun/feature_store/feature_vector.py +1 -1
  18. mlrun/feature_store/retrieval/base.py +8 -3
  19. mlrun/launcher/remote.py +3 -3
  20. mlrun/lists.py +11 -0
  21. mlrun/model_monitoring/__init__.py +0 -1
  22. mlrun/model_monitoring/api.py +1 -1
  23. mlrun/model_monitoring/application.py +313 -0
  24. mlrun/model_monitoring/batch_application.py +526 -0
  25. mlrun/model_monitoring/batch_application_handler.py +32 -0
  26. mlrun/model_monitoring/evidently_application.py +89 -0
  27. mlrun/model_monitoring/helpers.py +39 -3
  28. mlrun/model_monitoring/stores/kv_model_endpoint_store.py +37 -0
  29. mlrun/model_monitoring/tracking_policy.py +4 -4
  30. mlrun/model_monitoring/writer.py +37 -0
  31. mlrun/projects/pipelines.py +38 -4
  32. mlrun/projects/project.py +257 -43
  33. mlrun/run.py +5 -2
  34. mlrun/runtimes/__init__.py +2 -0
  35. mlrun/runtimes/function.py +2 -1
  36. mlrun/utils/helpers.py +12 -0
  37. mlrun/utils/http.py +3 -0
  38. mlrun/utils/version/version.json +2 -2
  39. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/METADATA +5 -5
  40. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/RECORD +45 -40
  41. /mlrun/model_monitoring/{model_monitoring_batch.py → batch.py} +0 -0
  42. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/LICENSE +0 -0
  43. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/WHEEL +0 -0
  44. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/entry_points.txt +0 -0
  45. {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/top_level.txt +0 -0
@@ -25,21 +25,27 @@ import mlrun.api.utils.scheduler
25
25
  import mlrun.api.utils.singletons.db
26
26
  import mlrun.api.utils.singletons.k8s
27
27
  import mlrun.common.schemas.model_monitoring
28
+ import mlrun.common.schemas.model_monitoring.constants as mm_constants
28
29
  import mlrun.model_monitoring.stream_processing
29
30
  import mlrun.model_monitoring.tracking_policy
30
31
  from mlrun import feature_store as fstore
31
32
  from mlrun.api.api import deps
32
33
  from mlrun.api.crud.model_monitoring.helpers import Seconds, seconds2minutes
34
+ from mlrun.model_monitoring.writer import ModelMonitoringWriter
33
35
  from mlrun.utils import logger
34
36
 
35
37
  _MODEL_MONITORING_COMMON_PATH = pathlib.Path(__file__).parents[3] / "model_monitoring"
36
38
  _STREAM_PROCESSING_FUNCTION_PATH = (
37
39
  _MODEL_MONITORING_COMMON_PATH / "stream_processing.py"
38
40
  )
39
- _MONITORING_BATCH_FUNCTION_PATH = (
40
- _MODEL_MONITORING_COMMON_PATH / "model_monitoring_batch.py"
41
+ _MONITORING_ORIGINAL_BATCH_FUNCTION_PATH = _MODEL_MONITORING_COMMON_PATH / "batch.py"
42
+
43
+ _MONITORING_APPLICATION_BATCH_FUNCTION_PATH = (
44
+ _MODEL_MONITORING_COMMON_PATH / "batch_application_handler.py"
41
45
  )
42
46
 
47
+ _MONITORING_WRITER_FUNCTION_PATH = _MODEL_MONITORING_COMMON_PATH / "writer.py"
48
+
43
49
 
44
50
  class MonitoringDeployment:
45
51
  def __init__(
@@ -50,8 +56,11 @@ class MonitoringDeployment:
50
56
  self._parquet_batching_max_events = parquet_batching_max_events
51
57
  self._max_parquet_save_interval = max_parquet_save_interval
52
58
  """
53
- Initialize a MonitoringDeployment object, which handles the deployment of both model monitoring stream nuclio
54
- function and the scheduled batch drift job.
59
+ Initialize a MonitoringDeployment object, which handles the deployment & scheduling of:
60
+ 1. model monitoring stream
61
+ 2. model monitoring batch
62
+ 3. model monitoring batch application
63
+ 4. model monitoring writer
55
64
 
56
65
  :param parquet_batching_max_events: Maximum number of events that will be used for writing the monitoring
57
66
  parquet by the monitoring stream function.
@@ -91,7 +100,25 @@ class MonitoringDeployment:
91
100
  auth_info=auth_info,
92
101
  tracking_policy=tracking_policy,
93
102
  tracking_offset=Seconds(self._max_parquet_save_interval),
103
+ function_name=mm_constants.MonitoringFunctionNames.BATCH,
94
104
  )
105
+ if tracking_policy.application_batch:
106
+ self.deploy_model_monitoring_batch_processing(
107
+ project=project,
108
+ model_monitoring_access_key=model_monitoring_access_key,
109
+ db_session=db_session,
110
+ auth_info=auth_info,
111
+ tracking_policy=tracking_policy,
112
+ tracking_offset=Seconds(self._max_parquet_save_interval),
113
+ function_name=mm_constants.MonitoringFunctionNames.BATCH_APPLICATION,
114
+ )
115
+ self.deploy_model_monitoring_writer_application(
116
+ project=project,
117
+ model_monitoring_access_key=model_monitoring_access_key,
118
+ db_session=db_session,
119
+ auth_info=auth_info,
120
+ tracking_policy=tracking_policy,
121
+ )
95
122
 
96
123
  def deploy_model_monitoring_stream_processing(
97
124
  self,
@@ -154,7 +181,9 @@ class MonitoringDeployment:
154
181
  fn.metadata.labels = {"type": "model-monitoring-stream"}
155
182
 
156
183
  mlrun.api.api.endpoints.functions._build_function(
157
- db_session=db_session, auth_info=auth_info, function=fn
184
+ db_session=db_session,
185
+ auth_info=auth_info,
186
+ function=fn,
158
187
  )
159
188
 
160
189
  def deploy_model_monitoring_batch_processing(
@@ -167,12 +196,14 @@ class MonitoringDeployment:
167
196
  with_schedule: bool = True,
168
197
  overwrite: bool = False,
169
198
  tracking_offset: Seconds = Seconds(0),
199
+ function_name: str = mm_constants.MonitoringFunctionNames.BATCH,
170
200
  ) -> typing.Union[mlrun.runtimes.kubejob.KubejobRuntime, None]:
171
201
  """
172
- Deploying model monitoring batch job. The goal of this job is to identify drift in the data
173
- based on the latest batch of events. By default, this job is executed on the hour every hour.
174
- Note that if the monitoring batch job was already deployed then you will either have to pass overwrite=True or
175
- to delete the old monitoring batch job before deploying a new one.
202
+ Deploying model monitoring batch job or model monitoring batch application job.
203
+ The goal of this job is to identify drift in the data based on the latest batch of events. By default,
204
+ this job is executed on the hour every hour.
205
+ Note that if this job was already deployed then you will either have to pass overwrite=True or
206
+ to delete the old job before deploying a new one.
176
207
 
177
208
  :param project: The name of the project.
178
209
  :param model_monitoring_access_key: Access key to apply the model monitoring process.
@@ -182,14 +213,23 @@ class MonitoringDeployment:
182
213
  :param with_schedule: If true, submit a scheduled batch drift job.
183
214
  :param overwrite: If true, overwrite the existing model monitoring batch job.
184
215
  :param tracking_offset: Offset for the tracking policy (for synchronization with the stream)
216
+ :param function_name: model-monitoring-batch or model-monitoring-application-batch
217
+ indicates witch one to deploy.
185
218
 
186
219
  :return: Model monitoring batch job as a runtime function.
187
220
  """
188
-
221
+ job_valid_names = [
222
+ mm_constants.MonitoringFunctionNames.BATCH,
223
+ mm_constants.MonitoringFunctionNames.BATCH_APPLICATION,
224
+ ]
225
+ if function_name not in job_valid_names:
226
+ raise mlrun.errors.MLRunRuntimeError(
227
+ f"Model Monitoring batch job can be only within {job_valid_names}"
228
+ )
189
229
  fn = None
190
230
  if not overwrite:
191
231
  logger.info(
192
- "Checking if model monitoring batch processing function is already deployed",
232
+ f"Checking if {function_name.replace('-',' ')} processing function is already deployed",
193
233
  project=project,
194
234
  )
195
235
 
@@ -198,17 +238,18 @@ class MonitoringDeployment:
198
238
  try:
199
239
  fn = mlrun.api.crud.Functions().get_function(
200
240
  db_session=db_session,
201
- name="model-monitoring-batch",
241
+ name=function_name,
202
242
  project=project,
203
243
  )
204
244
  logger.info(
205
- "Detected model monitoring batch processing function already deployed",
245
+ f"Detected {function_name.replace('-',' ')} processing function already deployed",
206
246
  project=project,
207
247
  )
208
248
 
209
249
  except mlrun.errors.MLRunNotFoundError:
210
250
  logger.info(
211
- "Deploying monitoring batch processing function ", project=project
251
+ f"Deploying {function_name.replace('-',' ')} processing function ",
252
+ project=project,
212
253
  )
213
254
 
214
255
  if not fn:
@@ -219,6 +260,7 @@ class MonitoringDeployment:
219
260
  db_session=db_session,
220
261
  auth_info=auth_info,
221
262
  tracking_policy=tracking_policy,
263
+ function_name=function_name,
222
264
  )
223
265
 
224
266
  # Get the function uri
@@ -230,16 +272,16 @@ class MonitoringDeployment:
230
272
  mlrun.api.utils.scheduler.Scheduler().get_schedule(
231
273
  db_session=db_session,
232
274
  project=project,
233
- name="model-monitoring-batch",
275
+ name=function_name,
234
276
  )
235
277
  logger.info(
236
- "Already deployed monitoring batch scheduled job function ",
278
+ f"Already deployed {function_name.replace('-',' ')} scheduled job function ",
237
279
  project=project,
238
280
  )
239
281
  return
240
282
  except mlrun.errors.MLRunNotFoundError:
241
283
  logger.info(
242
- "Deploying monitoring batch scheduled job function ",
284
+ f"Deploying {function_name.replace('-',' ')} scheduled job function ",
243
285
  project=project,
244
286
  )
245
287
  # Submit batch scheduled job
@@ -250,9 +292,68 @@ class MonitoringDeployment:
250
292
  auth_info=auth_info,
251
293
  tracking_policy=tracking_policy,
252
294
  tracking_offset=tracking_offset,
295
+ function_name=function_name,
253
296
  )
254
297
  return fn
255
298
 
299
+ def deploy_model_monitoring_writer_application(
300
+ self,
301
+ project,
302
+ model_monitoring_access_key,
303
+ db_session,
304
+ auth_info,
305
+ tracking_policy,
306
+ ):
307
+ """
308
+ Deploying model monitoring writer real time nuclio function. The goal of this real time function is
309
+ to write all the monitoring application result to the databases. It is triggered by those applications.
310
+ It processes and writes the result to the databases.
311
+
312
+ :param project: The name of the project.
313
+ :param model_monitoring_access_key: Access key to apply the model monitoring process.
314
+ :param db_session: A session that manages the current dialog with the database.
315
+ :param auth_info: The auth info of the request.
316
+ :param tracking_policy: Model monitoring configurations.
317
+ """
318
+
319
+ logger.info(
320
+ "Checking if model monitoring writer is already deployed",
321
+ project=project,
322
+ )
323
+ try:
324
+ # validate that the model monitoring stream has not yet been deployed
325
+ mlrun.runtimes.function.get_nuclio_deploy_status(
326
+ name=mm_constants.MonitoringFunctionNames.WRITER,
327
+ project=project,
328
+ tag="",
329
+ auth_info=auth_info,
330
+ )
331
+ logger.info(
332
+ "Detected model monitoring writer processing function already deployed",
333
+ project=project,
334
+ )
335
+ return
336
+ except mlrun.errors.MLRunNotFoundError:
337
+ logger.info(
338
+ "Deploying model monitoring writer processing function", project=project
339
+ )
340
+
341
+ fn = self._initial_model_monitoring_writer_function(
342
+ project=project,
343
+ model_monitoring_access_key=model_monitoring_access_key,
344
+ tracking_policy=tracking_policy,
345
+ auth_info=auth_info,
346
+ )
347
+
348
+ # Adding label to the function - will be used to identify the stream pod
349
+ fn.metadata.labels = {"type": "model-monitoring-writer"}
350
+
351
+ mlrun.api.api.endpoints.functions._build_function(
352
+ db_session=db_session,
353
+ auth_info=auth_info,
354
+ function=fn,
355
+ )
356
+
256
357
  def _initial_model_monitoring_stream_processing_function(
257
358
  self,
258
359
  project: str,
@@ -323,6 +424,7 @@ class MonitoringDeployment:
323
424
  db_session: sqlalchemy.orm.Session,
324
425
  auth_info: mlrun.common.schemas.AuthInfo,
325
426
  tracking_policy: mlrun.model_monitoring.tracking_policy.TrackingPolicy,
427
+ function_name: str = "model-monitoring-batch",
326
428
  ):
327
429
  """
328
430
  Initialize model monitoring batch function.
@@ -333,16 +435,21 @@ class MonitoringDeployment:
333
435
  :param db_session: A session that manages the current dialog with the database.
334
436
  :param auth_info: The auth info of the request.
335
437
  :param tracking_policy: Model monitoring configurations.
336
-
438
+ :param function_name: model-monitoring-batch or model-monitoring-application-batch
439
+ indicates witch one to create.
337
440
  :return: A function object from a mlrun runtime class
338
441
 
339
442
  """
340
-
443
+ filename = (
444
+ str(_MONITORING_ORIGINAL_BATCH_FUNCTION_PATH)
445
+ if function_name == "model-monitoring-batch"
446
+ else str(_MONITORING_APPLICATION_BATCH_FUNCTION_PATH)
447
+ )
341
448
  # Create job function runtime for the model monitoring batch
342
449
  function: mlrun.runtimes.KubejobRuntime = mlrun.code_to_function(
343
- name="model-monitoring-batch",
450
+ name=function_name,
344
451
  project=project,
345
- filename=str(_MONITORING_BATCH_FUNCTION_PATH),
452
+ filename=filename,
346
453
  kind="job",
347
454
  image=tracking_policy.default_batch_image,
348
455
  handler="handler",
@@ -358,6 +465,7 @@ class MonitoringDeployment:
358
465
  function=function,
359
466
  model_monitoring_access_key=model_monitoring_access_key,
360
467
  auth_info=auth_info,
468
+ function_name=function_name,
361
469
  )
362
470
 
363
471
  # Enrich runtime with the required configurations
@@ -375,6 +483,7 @@ class MonitoringDeployment:
375
483
  auth_info: mlrun.common.schemas.AuthInfo,
376
484
  tracking_policy: mlrun.model_monitoring.tracking_policy.TrackingPolicy,
377
485
  tracking_offset: Seconds = Seconds(0),
486
+ function_name: str = "model-monitoring-batch",
378
487
  ):
379
488
  """
380
489
  Create a new scheduled monitoring batch job analysis based on the model-monitoring-batch function that has
@@ -392,7 +501,7 @@ class MonitoringDeployment:
392
501
 
393
502
  function_uri = function_uri.replace("db://", "")
394
503
 
395
- task = mlrun.new_task(name="model-monitoring-batch", project=project)
504
+ task = mlrun.new_task(name=function_name, project=project)
396
505
  task.spec.function = function_uri
397
506
 
398
507
  # Apply batching interval params
@@ -423,7 +532,8 @@ class MonitoringDeployment:
423
532
  }
424
533
 
425
534
  logger.info(
426
- "Deploying model monitoring batch processing function", project=project
535
+ f"Deploying {function_name.replace('-',' ')} processing function",
536
+ project=project,
427
537
  )
428
538
 
429
539
  # Add job schedule policy (every hour by default)
@@ -437,6 +547,7 @@ class MonitoringDeployment:
437
547
  function: mlrun.runtimes.ServingRuntime,
438
548
  model_monitoring_access_key: str = None,
439
549
  auth_info: mlrun.common.schemas.AuthInfo = Depends(deps.authenticate_request),
550
+ function_name: str = None,
440
551
  ) -> mlrun.runtimes.ServingRuntime:
441
552
  """Adding stream source for the nuclio serving function. By default, the function has HTTP stream trigger along
442
553
  with another supported stream source that can be either Kafka or V3IO, depends on the stream path schema that is
@@ -448,13 +559,17 @@ class MonitoringDeployment:
448
559
  :param model_monitoring_access_key: Access key to apply the model monitoring stream function when the stream is
449
560
  schema is V3IO.
450
561
  :param auth_info: The auth info of the request.
562
+ :param function_name: the name of the function that be applied with the stream trigger,
563
+ None for model_monitoring_stream
451
564
 
452
565
  :return: ServingRuntime object with stream trigger.
453
566
  """
454
567
 
455
568
  # Get the stream path from the configuration
456
569
  # stream_path = mlrun.mlconf.get_file_target_path(project=project, kind="stream", target="stream")
457
- stream_path = mlrun.api.crud.model_monitoring.get_stream_path(project=project)
570
+ stream_path = mlrun.api.crud.model_monitoring.get_stream_path(
571
+ project=project, application_name=function_name
572
+ )
458
573
 
459
574
  if stream_path.startswith("kafka://"):
460
575
  topic, brokers = mlrun.datastore.utils.parse_kafka_url(url=stream_path)
@@ -471,11 +586,18 @@ class MonitoringDeployment:
471
586
  function=function,
472
587
  model_monitoring_access_key=model_monitoring_access_key,
473
588
  auth_info=auth_info,
589
+ function_name=function_name,
474
590
  )
475
591
  if stream_path.startswith("v3io://"):
476
592
  # Generate V3IO stream trigger
477
593
  function.add_v3io_stream_trigger(
478
- stream_path=stream_path, name="monitoring_stream_trigger"
594
+ stream_path=stream_path,
595
+ name="monitoring_stream_trigger"
596
+ if function_name is None
597
+ else f"monitoring_{function_name}_trigger",
598
+ access_key=model_monitoring_access_key
599
+ if function_name != mm_constants.MonitoringFunctionNames.STREAM
600
+ else None,
479
601
  )
480
602
  # Add the default HTTP source
481
603
  http_source = mlrun.datastore.sources.HttpSource()
@@ -491,6 +613,7 @@ class MonitoringDeployment:
491
613
  ],
492
614
  model_monitoring_access_key: str,
493
615
  auth_info: mlrun.common.schemas.AuthInfo,
616
+ function_name: str = None,
494
617
  ) -> typing.Union[mlrun.runtimes.KubejobRuntime, mlrun.runtimes.ServingRuntime]:
495
618
  """Applying model monitoring access key on the provided function when using V3IO path. In addition, this method
496
619
  mount the V3IO path for the provided function to configure the access to the system files.
@@ -505,23 +628,70 @@ class MonitoringDeployment:
505
628
  :return: function runtime object with access key and access to system files.
506
629
  """
507
630
 
508
- # Set model monitoring access key for managing permissions
509
- function.set_env_from_secret(
510
- mlrun.common.schemas.model_monitoring.ProjectSecretKeys.ACCESS_KEY,
511
- mlrun.api.utils.singletons.k8s.get_k8s_helper().get_project_secret_name(
512
- project
513
- ),
514
- mlrun.api.crud.secrets.Secrets().generate_client_project_secret_key(
515
- mlrun.api.crud.secrets.SecretsClientType.model_monitoring,
631
+ if function_name in mm_constants.MonitoringFunctionNames.all():
632
+ # Set model monitoring access key for managing permissions
633
+ function.set_env_from_secret(
516
634
  mlrun.common.schemas.model_monitoring.ProjectSecretKeys.ACCESS_KEY,
517
- ),
635
+ mlrun.api.utils.singletons.k8s.get_k8s_helper().get_project_secret_name(
636
+ project
637
+ ),
638
+ mlrun.api.crud.secrets.Secrets().generate_client_project_secret_key(
639
+ mlrun.api.crud.secrets.SecretsClientType.model_monitoring,
640
+ mlrun.common.schemas.model_monitoring.ProjectSecretKeys.ACCESS_KEY,
641
+ ),
642
+ )
643
+
644
+ function.metadata.credentials.access_key = model_monitoring_access_key
645
+ function.apply(mlrun.v3io_cred())
646
+
647
+ # Ensure that the auth env vars are set
648
+ mlrun.api.api.utils.ensure_function_has_auth_set(function, auth_info)
649
+ return function
650
+
651
+ def _initial_model_monitoring_writer_function(
652
+ self, project, model_monitoring_access_key, tracking_policy, auth_info
653
+ ):
654
+ """
655
+ Initialize model monitoring writer function.
656
+
657
+ :param project: Project name.
658
+ :param model_monitoring_access_key: Access key to apply the model monitoring process. Please note that in CE
659
+ deployments this parameter will be None.
660
+ :param tracking_policy: Model monitoring configurations.
661
+ :param auth_info: The auth info of the request.
662
+
663
+ :return: A function object from a mlrun runtime class
664
+
665
+ """
666
+
667
+ # Create a new serving function for the streaming process
668
+ function = mlrun.code_to_function(
669
+ name=mm_constants.MonitoringFunctionNames.WRITER,
670
+ project=project,
671
+ filename=str(_MONITORING_WRITER_FUNCTION_PATH),
672
+ kind="serving",
673
+ image=tracking_policy.stream_image,
518
674
  )
519
675
 
520
- function.metadata.credentials.access_key = model_monitoring_access_key
521
- function.apply(mlrun.mount_v3io())
676
+ # Create writer monitoring serving graph
677
+ graph = function.set_topology("flow")
678
+ graph.to(ModelMonitoringWriter(name="king")).respond() # writer
679
+
680
+ # Set the project to the serving function
681
+ function.metadata.project = project
522
682
 
523
- # Ensure that the auth env vars are set
524
- mlrun.api.api.utils.ensure_function_has_auth_set(function, auth_info)
683
+ # Add stream triggers
684
+ function = self._apply_stream_trigger(
685
+ project=project,
686
+ function=function,
687
+ model_monitoring_access_key=model_monitoring_access_key,
688
+ auth_info=auth_info,
689
+ function_name=mm_constants.MonitoringFunctionNames.WRITER,
690
+ )
691
+
692
+ # Apply feature store run configurations on the serving function
693
+ run_config = fstore.RunConfig(function=function, local=False)
694
+ function.spec.parameters = run_config.parameters
525
695
 
526
696
  return function
527
697
 
@@ -112,7 +112,9 @@ def get_access_key(auth_info: mlrun.common.schemas.AuthInfo):
112
112
 
113
113
 
114
114
  def get_monitoring_parquet_path(
115
- db_session: sqlalchemy.orm.Session, project: str
115
+ db_session: sqlalchemy.orm.Session,
116
+ project: str,
117
+ kind: str = mlrun.common.schemas.model_monitoring.FileTargetKind.PARQUET,
116
118
  ) -> str:
117
119
  """Get model monitoring parquet target for the current project. The parquet target path is based on the
118
120
  project artifact path. If project artifact path is not defined, the parquet target path will be based on MLRun
@@ -121,6 +123,7 @@ def get_monitoring_parquet_path(
121
123
  :param db_session: A session that manages the current dialog with the database. Will be used in this function
122
124
  to get the project record from DB.
123
125
  :param project: Project name.
126
+ :param kind: indicate the kind of the parquet path, can be either stream_parquet or stream_controller_parquet
124
127
 
125
128
  :return: Monitoring parquet target path.
126
129
  """
@@ -133,27 +136,37 @@ def get_monitoring_parquet_path(
133
136
  # Generate monitoring parquet path value
134
137
  parquet_path = mlrun.mlconf.get_model_monitoring_file_target_path(
135
138
  project=project,
136
- kind=mlrun.common.schemas.model_monitoring.FileTargetKind.PARQUET,
139
+ kind=kind,
137
140
  target="offline",
138
141
  artifact_path=artifact_path,
139
142
  )
140
143
  return parquet_path
141
144
 
142
145
 
143
- def get_stream_path(project: str = None):
144
- """Get stream path from the project secret. If wasn't set, take it from the system configurations"""
146
+ def get_stream_path(project: str = None, application_name: str = None):
147
+ """
148
+ Get stream path from the project secret. If wasn't set, take it from the system configurations
149
+
150
+ :param project: Project name.
151
+ :param application_name: Application name, None for model_monitoring_stream.
152
+
153
+ :return: Monitoring stream path to the relevant application.
154
+ """
145
155
 
146
156
  stream_uri = mlrun.api.crud.secrets.Secrets().get_project_secret(
147
157
  project=project,
148
158
  provider=mlrun.common.schemas.secret.SecretProviderName.kubernetes,
149
159
  allow_secrets_from_k8s=True,
150
- secret_key=mlrun.common.schemas.model_monitoring.ProjectSecretKeys.STREAM_PATH,
160
+ secret_key=mlrun.common.schemas.model_monitoring.ProjectSecretKeys.STREAM_PATH
161
+ if application_name is None
162
+ else "",
151
163
  ) or mlrun.mlconf.get_model_monitoring_file_target_path(
152
164
  project=project,
153
165
  kind=mlrun.common.schemas.model_monitoring.FileTargetKind.STREAM,
154
166
  target="online",
167
+ application_name=application_name,
155
168
  )
156
169
 
157
170
  return mlrun.common.model_monitoring.helpers.parse_monitoring_stream_path(
158
- stream_uri=stream_uri, project=project
171
+ stream_uri=stream_uri, project=project, application_name=application_name
159
172
  )
@@ -72,6 +72,12 @@ class ModelEndpoints:
72
72
  )
73
73
  )
74
74
 
75
+ mlrun.utils.helpers.verify_field_of_type(
76
+ field_name="model_endpoint.spec.model_uri",
77
+ field_value=model_obj,
78
+ expected_type=mlrun.artifacts.ModelArtifact,
79
+ )
80
+
75
81
  # Get stats from model object if not found in model endpoint object
76
82
  if not model_endpoint.status.feature_stats and hasattr(
77
83
  model_obj, "feature_stats"
@@ -238,6 +244,12 @@ class ModelEndpoints:
238
244
  name=feature.name, value_type=feature.value_type
239
245
  )
240
246
  )
247
+ for feature in model_obj.spec.outputs:
248
+ feature_set.add_feature(
249
+ mlrun.feature_store.Feature(
250
+ name=feature.name, value_type=feature.value_type
251
+ )
252
+ )
241
253
  # Check if features can be found within the feature vector
242
254
  elif model_obj.spec.feature_vector:
243
255
  _, name, _, tag, _ = mlrun.utils.helpers.parse_artifact_uri(
@@ -267,7 +279,8 @@ class ModelEndpoints:
267
279
  )
268
280
 
269
281
  parquet_target = mlrun.datastore.targets.ParquetTarget(
270
- mlrun.common.schemas.model_monitoring.FileTargetKind.PARQUET, parquet_path
282
+ mlrun.common.schemas.model_monitoring.FileTargetKind.PARQUET,
283
+ parquet_path,
271
284
  )
272
285
  driver = mlrun.datastore.targets.get_target_driver(parquet_target, feature_set)
273
286
 
mlrun/api/db/sqldb/db.py CHANGED
@@ -304,7 +304,9 @@ class SQLDB(DBInterface):
304
304
  project = project or config.default_project
305
305
  run = self._get_run(session, uid, project, iter)
306
306
  if not run:
307
- raise mlrun.errors.MLRunNotFoundError(f"Run {uid}:{project} not found")
307
+ raise mlrun.errors.MLRunNotFoundError(
308
+ f"Run uid {uid} of project {project} not found"
309
+ )
308
310
  return run.struct
309
311
 
310
312
  def list_runs(
@@ -673,10 +673,8 @@ def build_runtime(
673
673
  base_image: str = (
674
674
  build.base_image or runtime.spec.image or config.default_base_image
675
675
  )
676
- enriched_base_image = mlrun.utils.enrich_image_url(
677
- base_image,
678
- client_version,
679
- client_python_version,
676
+ enriched_base_image = runtime.full_image_path(
677
+ base_image, client_version, client_python_version
680
678
  )
681
679
  mlrun.utils.logger.info(
682
680
  "Building runtime image",
@@ -64,20 +64,34 @@ def parse_model_endpoint_store_prefix(store_prefix: str):
64
64
  return endpoint, container, path
65
65
 
66
66
 
67
- def parse_monitoring_stream_path(stream_uri: str, project: str):
67
+ def parse_monitoring_stream_path(
68
+ stream_uri: str, project: str, application_name: str = None
69
+ ):
68
70
  if stream_uri.startswith("kafka://"):
69
71
  if "?topic" in stream_uri:
70
72
  raise mlrun.errors.MLRunInvalidArgumentError(
71
73
  "Custom kafka topic is not allowed"
72
74
  )
73
75
  # Add topic to stream kafka uri
74
- stream_uri += f"?topic=monitoring_stream_{project}"
76
+ if application_name is None:
77
+ stream_uri += f"?topic=monitoring_stream_{project}"
78
+ else:
79
+ stream_uri += f"?topic=monitoring_stream_{project}_{application_name}"
75
80
 
76
81
  elif stream_uri.startswith("v3io://") and mlrun.mlconf.is_ce_mode():
77
82
  # V3IO is not supported in CE mode, generating a default http stream path
78
- stream_uri = mlrun.mlconf.model_endpoint_monitoring.default_http_sink.format(
79
- project=project
80
- )
83
+ if application_name is None:
84
+ stream_uri = (
85
+ mlrun.mlconf.model_endpoint_monitoring.default_http_sink.format(
86
+ project=project
87
+ )
88
+ )
89
+ else:
90
+ stream_uri = (
91
+ mlrun.mlconf.model_endpoint_monitoring.default_http_sink_app.format(
92
+ project=project, application_name=application_name
93
+ )
94
+ )
81
95
  return stream_uri
82
96
 
83
97