mlrun 1.10.0rc18__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 (167) hide show
  1. mlrun/__init__.py +24 -3
  2. mlrun/__main__.py +0 -4
  3. mlrun/artifacts/dataset.py +2 -2
  4. mlrun/artifacts/document.py +6 -1
  5. mlrun/artifacts/llm_prompt.py +21 -15
  6. mlrun/artifacts/model.py +3 -3
  7. mlrun/artifacts/plots.py +1 -1
  8. mlrun/{model_monitoring/db/tsdb/tdengine → auth}/__init__.py +2 -3
  9. mlrun/auth/nuclio.py +89 -0
  10. mlrun/auth/providers.py +429 -0
  11. mlrun/auth/utils.py +415 -0
  12. mlrun/common/constants.py +14 -0
  13. mlrun/common/model_monitoring/helpers.py +123 -0
  14. mlrun/common/runtimes/constants.py +28 -0
  15. mlrun/common/schemas/__init__.py +14 -3
  16. mlrun/common/schemas/alert.py +2 -2
  17. mlrun/common/schemas/api_gateway.py +3 -0
  18. mlrun/common/schemas/auth.py +12 -10
  19. mlrun/common/schemas/client_spec.py +4 -0
  20. mlrun/common/schemas/constants.py +25 -0
  21. mlrun/common/schemas/frontend_spec.py +1 -8
  22. mlrun/common/schemas/function.py +34 -0
  23. mlrun/common/schemas/hub.py +33 -20
  24. mlrun/common/schemas/model_monitoring/__init__.py +2 -1
  25. mlrun/common/schemas/model_monitoring/constants.py +12 -15
  26. mlrun/common/schemas/model_monitoring/functions.py +13 -4
  27. mlrun/common/schemas/model_monitoring/model_endpoints.py +11 -0
  28. mlrun/common/schemas/pipeline.py +1 -1
  29. mlrun/common/schemas/secret.py +17 -2
  30. mlrun/common/secrets.py +95 -1
  31. mlrun/common/types.py +10 -10
  32. mlrun/config.py +69 -19
  33. mlrun/data_types/infer.py +2 -2
  34. mlrun/datastore/__init__.py +12 -5
  35. mlrun/datastore/azure_blob.py +162 -47
  36. mlrun/datastore/base.py +274 -10
  37. mlrun/datastore/datastore.py +7 -2
  38. mlrun/datastore/datastore_profile.py +84 -22
  39. mlrun/datastore/model_provider/huggingface_provider.py +225 -41
  40. mlrun/datastore/model_provider/mock_model_provider.py +87 -0
  41. mlrun/datastore/model_provider/model_provider.py +206 -74
  42. mlrun/datastore/model_provider/openai_provider.py +226 -66
  43. mlrun/datastore/s3.py +39 -18
  44. mlrun/datastore/sources.py +1 -1
  45. mlrun/datastore/store_resources.py +4 -4
  46. mlrun/datastore/storeytargets.py +17 -12
  47. mlrun/datastore/targets.py +1 -1
  48. mlrun/datastore/utils.py +25 -6
  49. mlrun/datastore/v3io.py +1 -1
  50. mlrun/db/base.py +63 -32
  51. mlrun/db/httpdb.py +373 -153
  52. mlrun/db/nopdb.py +54 -21
  53. mlrun/errors.py +4 -2
  54. mlrun/execution.py +66 -25
  55. mlrun/feature_store/api.py +1 -1
  56. mlrun/feature_store/common.py +1 -1
  57. mlrun/feature_store/feature_vector_utils.py +1 -1
  58. mlrun/feature_store/steps.py +8 -6
  59. mlrun/frameworks/_common/utils.py +3 -3
  60. mlrun/frameworks/_dl_common/loggers/logger.py +1 -1
  61. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +2 -1
  62. mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +1 -1
  63. mlrun/frameworks/_ml_common/utils.py +2 -1
  64. mlrun/frameworks/auto_mlrun/auto_mlrun.py +4 -3
  65. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +2 -1
  66. mlrun/frameworks/onnx/dataset.py +2 -1
  67. mlrun/frameworks/onnx/mlrun_interface.py +2 -1
  68. mlrun/frameworks/pytorch/callbacks/logging_callback.py +5 -4
  69. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +2 -1
  70. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +2 -1
  71. mlrun/frameworks/pytorch/utils.py +2 -1
  72. mlrun/frameworks/sklearn/metric.py +2 -1
  73. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +5 -4
  74. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +2 -1
  75. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +2 -1
  76. mlrun/hub/__init__.py +52 -0
  77. mlrun/hub/base.py +142 -0
  78. mlrun/hub/module.py +172 -0
  79. mlrun/hub/step.py +113 -0
  80. mlrun/k8s_utils.py +105 -16
  81. mlrun/launcher/base.py +15 -7
  82. mlrun/launcher/local.py +4 -1
  83. mlrun/model.py +14 -4
  84. mlrun/model_monitoring/__init__.py +0 -1
  85. mlrun/model_monitoring/api.py +65 -28
  86. mlrun/model_monitoring/applications/__init__.py +1 -1
  87. mlrun/model_monitoring/applications/base.py +299 -128
  88. mlrun/model_monitoring/applications/context.py +2 -4
  89. mlrun/model_monitoring/controller.py +132 -58
  90. mlrun/model_monitoring/db/_schedules.py +38 -29
  91. mlrun/model_monitoring/db/_stats.py +6 -16
  92. mlrun/model_monitoring/db/tsdb/__init__.py +9 -7
  93. mlrun/model_monitoring/db/tsdb/base.py +29 -9
  94. mlrun/model_monitoring/db/tsdb/preaggregate.py +234 -0
  95. mlrun/model_monitoring/db/tsdb/stream_graph_steps.py +63 -0
  96. mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_metrics_queries.py +414 -0
  97. mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_predictions_queries.py +376 -0
  98. mlrun/model_monitoring/db/tsdb/timescaledb/queries/timescaledb_results_queries.py +590 -0
  99. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_connection.py +434 -0
  100. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_connector.py +541 -0
  101. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_operations.py +808 -0
  102. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_schema.py +502 -0
  103. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_stream.py +163 -0
  104. mlrun/model_monitoring/db/tsdb/timescaledb/timescaledb_stream_graph_steps.py +60 -0
  105. mlrun/model_monitoring/db/tsdb/timescaledb/utils/timescaledb_dataframe_processor.py +141 -0
  106. mlrun/model_monitoring/db/tsdb/timescaledb/utils/timescaledb_query_builder.py +585 -0
  107. mlrun/model_monitoring/db/tsdb/timescaledb/writer_graph_steps.py +73 -0
  108. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +20 -9
  109. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +235 -51
  110. mlrun/model_monitoring/features_drift_table.py +2 -1
  111. mlrun/model_monitoring/helpers.py +30 -6
  112. mlrun/model_monitoring/stream_processing.py +34 -28
  113. mlrun/model_monitoring/writer.py +224 -4
  114. mlrun/package/__init__.py +2 -1
  115. mlrun/platforms/__init__.py +0 -43
  116. mlrun/platforms/iguazio.py +8 -4
  117. mlrun/projects/operations.py +17 -11
  118. mlrun/projects/pipelines.py +2 -2
  119. mlrun/projects/project.py +187 -123
  120. mlrun/run.py +95 -21
  121. mlrun/runtimes/__init__.py +2 -186
  122. mlrun/runtimes/base.py +103 -25
  123. mlrun/runtimes/constants.py +225 -0
  124. mlrun/runtimes/daskjob.py +5 -2
  125. mlrun/runtimes/databricks_job/databricks_runtime.py +2 -1
  126. mlrun/runtimes/local.py +5 -2
  127. mlrun/runtimes/mounts.py +20 -2
  128. mlrun/runtimes/nuclio/__init__.py +12 -7
  129. mlrun/runtimes/nuclio/api_gateway.py +36 -6
  130. mlrun/runtimes/nuclio/application/application.py +339 -40
  131. mlrun/runtimes/nuclio/function.py +222 -72
  132. mlrun/runtimes/nuclio/serving.py +132 -42
  133. mlrun/runtimes/pod.py +213 -21
  134. mlrun/runtimes/utils.py +49 -9
  135. mlrun/secrets.py +99 -14
  136. mlrun/serving/__init__.py +2 -0
  137. mlrun/serving/remote.py +84 -11
  138. mlrun/serving/routers.py +26 -44
  139. mlrun/serving/server.py +138 -51
  140. mlrun/serving/serving_wrapper.py +6 -2
  141. mlrun/serving/states.py +997 -283
  142. mlrun/serving/steps.py +62 -0
  143. mlrun/serving/system_steps.py +149 -95
  144. mlrun/serving/v2_serving.py +9 -10
  145. mlrun/track/trackers/mlflow_tracker.py +29 -31
  146. mlrun/utils/helpers.py +292 -94
  147. mlrun/utils/http.py +9 -2
  148. mlrun/utils/notifications/notification/base.py +18 -0
  149. mlrun/utils/notifications/notification/git.py +3 -5
  150. mlrun/utils/notifications/notification/mail.py +39 -16
  151. mlrun/utils/notifications/notification/slack.py +2 -4
  152. mlrun/utils/notifications/notification/webhook.py +2 -5
  153. mlrun/utils/notifications/notification_pusher.py +3 -3
  154. mlrun/utils/version/version.json +2 -2
  155. mlrun/utils/version/version.py +3 -4
  156. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/METADATA +63 -74
  157. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/RECORD +161 -143
  158. mlrun/api/schemas/__init__.py +0 -259
  159. mlrun/db/auth_utils.py +0 -152
  160. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +0 -344
  161. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +0 -75
  162. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py +0 -281
  163. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +0 -1266
  164. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/WHEEL +0 -0
  165. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/entry_points.txt +0 -0
  166. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/licenses/LICENSE +0 -0
  167. {mlrun-1.10.0rc18.dist-info → mlrun-1.11.0rc16.dist-info}/top_level.txt +0 -0
@@ -16,8 +16,11 @@ import asyncio
16
16
  import copy
17
17
  import json
18
18
  import typing
19
+ import warnings
20
+ from dataclasses import dataclass
19
21
  from datetime import datetime
20
22
  from time import sleep
23
+ from urllib.parse import urlparse, urlunparse
21
24
 
22
25
  import inflection
23
26
  import nuclio
@@ -29,12 +32,14 @@ from kubernetes import client
29
32
  from nuclio.deploy import find_dashboard_url, get_deploy_status
30
33
  from nuclio.triggers import V3IOStreamTrigger
31
34
 
35
+ import mlrun.auth.nuclio
36
+ import mlrun.common.constants
32
37
  import mlrun.db
33
38
  import mlrun.errors
34
39
  import mlrun.k8s_utils
35
40
  import mlrun.utils
36
41
  import mlrun.utils.helpers
37
- from mlrun.common.schemas import AuthInfo
42
+ from mlrun.common.schemas import AuthInfo, BatchingSpec
38
43
  from mlrun.config import config as mlconf
39
44
  from mlrun.errors import err_to_str
40
45
  from mlrun.lists import RunList
@@ -94,6 +99,13 @@ def min_nuclio_versions(*versions):
94
99
  return decorator
95
100
 
96
101
 
102
+ @dataclass
103
+ class AsyncSpec:
104
+ enabled: bool = True
105
+ max_connections: typing.Optional[int] = None
106
+ connection_availability_timeout: typing.Optional[int] = None
107
+
108
+
97
109
  class NuclioSpec(KubeResourceSpec):
98
110
  _dict_fields = KubeResourceSpec._dict_fields + [
99
111
  "min_replicas",
@@ -111,6 +123,7 @@ class NuclioSpec(KubeResourceSpec):
111
123
  "service_type",
112
124
  "add_templated_ingress_host_mode",
113
125
  "disable_default_http_trigger",
126
+ "auth",
114
127
  ]
115
128
 
116
129
  def __init__(
@@ -158,6 +171,7 @@ class NuclioSpec(KubeResourceSpec):
158
171
  graph=None,
159
172
  parameters=None,
160
173
  track_models=None,
174
+ auth=None,
161
175
  ):
162
176
  super().__init__(
163
177
  command=command,
@@ -214,6 +228,7 @@ class NuclioSpec(KubeResourceSpec):
214
228
  # When True it will set Nuclio spec.noBaseImagesPull to False (negative logic)
215
229
  # indicate that the base image should be pulled from the container registry (not cached)
216
230
  self.base_image_pull = False
231
+ self.auth = auth or {}
217
232
 
218
233
  def generate_nuclio_volumes(self):
219
234
  nuclio_volumes = []
@@ -298,29 +313,16 @@ class RemoteRuntime(KubeResource):
298
313
  return {}
299
314
 
300
315
  raw_config = copy.deepcopy(self.spec.config)
301
-
302
316
  for key, value in self.spec.config.items():
303
317
  if key.startswith("spec.triggers"):
304
- trigger_name = key.split(".")[-1]
305
-
306
- for path in SENSITIVE_PATHS_IN_TRIGGER_CONFIG:
307
- # Handle nested keys
308
- nested_keys = path.split("/")
309
- target = value
310
- for sub_key in nested_keys[:-1]:
311
- target = target.get(sub_key, {})
312
-
313
- last_key = nested_keys[-1]
314
- if last_key in target:
315
- sensitive_field = target[last_key]
316
- if sensitive_field.startswith(
317
- mlrun.model.Credentials.secret_reference_prefix
318
- ):
319
- # already masked
320
- continue
321
- target[last_key] = (
322
- f"{mlrun.model.Credentials.secret_reference_prefix}/spec/triggers/{trigger_name}/{path}"
323
- )
318
+ # support both types depending on the way how it was set
319
+ # sometimes trigger name is in the same key, sometimes it's nested in the value dict
320
+ if key == "spec.triggers":
321
+ for trigger_name, trigger_config in value.items():
322
+ self._mask_trigger_config(trigger_name, trigger_config)
323
+ else:
324
+ trigger_name = key.split(".")[-1]
325
+ self._mask_trigger_config(trigger_name, value)
324
326
 
325
327
  return raw_config
326
328
 
@@ -422,6 +424,18 @@ class RemoteRuntime(KubeResource):
422
424
  )
423
425
  """
424
426
  self.spec.build.source = source
427
+
428
+ code = (
429
+ self.spec.build.functionSourceCode if hasattr(self.spec, "build") else None
430
+ )
431
+ if code:
432
+ # Warn and clear any inline code so the archive is actually used
433
+ logger.warning(
434
+ "Cannot specify both code and source archive. Removing the code so the provided "
435
+ "source archive will be used instead."
436
+ )
437
+ self.spec.build.functionSourceCode = None
438
+
425
439
  # update handler in function_handler if needed
426
440
  if handler:
427
441
  self.spec.function_handler = handler
@@ -450,7 +464,7 @@ class RemoteRuntime(KubeResource):
450
464
 
451
465
  def with_http(
452
466
  self,
453
- workers: typing.Optional[int] = 8,
467
+ workers: typing.Optional[int] = None,
454
468
  port: typing.Optional[int] = None,
455
469
  host: typing.Optional[str] = None,
456
470
  paths: typing.Optional[list[str]] = None,
@@ -461,6 +475,8 @@ class RemoteRuntime(KubeResource):
461
475
  trigger_name: typing.Optional[str] = None,
462
476
  annotations: typing.Optional[typing.Mapping[str, str]] = None,
463
477
  extra_attributes: typing.Optional[typing.Mapping[str, str]] = None,
478
+ batching_spec: typing.Optional[BatchingSpec] = None,
479
+ async_spec: typing.Optional[AsyncSpec] = None,
464
480
  ):
465
481
  """update/add nuclio HTTP trigger settings
466
482
 
@@ -468,7 +484,8 @@ class RemoteRuntime(KubeResource):
468
484
  if the max time a request will wait for until it will start processing, gateway_timeout must be greater than
469
485
  the worker_timeout.
470
486
 
471
- :param workers: number of worker processes (default=8). set 0 to use Nuclio's default workers count
487
+ :param workers: Number of worker processes. Defaults to 8 in synchronous mode and
488
+ 1 in asynchronous mode. Set to 0 to use Nuclio’s default worker count.
472
489
  :param port: TCP port to listen on. by default, nuclio will choose a random port as long as
473
490
  the function service is NodePort. if the function service is ClusterIP, the port
474
491
  is ignored.
@@ -482,6 +499,12 @@ class RemoteRuntime(KubeResource):
482
499
  :param trigger_name: alternative nuclio trigger name
483
500
  :param annotations: key/value dict of ingress annotations
484
501
  :param extra_attributes: key/value dict of extra nuclio trigger attributes
502
+ :param batching_spec: BatchingSpec object that defines batching configuration.
503
+ By default, batching is disabled.
504
+
505
+ :param async_spec: AsyncSpec object defines async configuration. If number of max connections
506
+ won't be set, the default value will be set to 1000 according to nuclio default.
507
+
485
508
  :return: function object (self)
486
509
  """
487
510
  if self.disable_default_http_trigger:
@@ -489,11 +512,15 @@ class RemoteRuntime(KubeResource):
489
512
  "Adding HTTP trigger despite the default HTTP trigger creation being disabled"
490
513
  )
491
514
 
515
+ if async_spec and async_spec.enabled:
516
+ workers = 1 if workers is None else workers
517
+ else:
518
+ workers = 8 if workers is None else workers
519
+
492
520
  annotations = annotations or {}
493
521
  if worker_timeout:
494
522
  gateway_timeout = gateway_timeout or (worker_timeout + 60)
495
- if workers is None:
496
- workers = 0
523
+
497
524
  if gateway_timeout:
498
525
  if worker_timeout and worker_timeout >= gateway_timeout:
499
526
  raise ValueError(
@@ -517,6 +544,28 @@ class RemoteRuntime(KubeResource):
517
544
  trigger._struct["workerAvailabilityTimeoutMilliseconds"] = (
518
545
  worker_timeout
519
546
  ) * 1000
547
+
548
+ if batching_spec and (
549
+ batching_config := batching_spec.get_nuclio_batch_config()
550
+ ):
551
+ if not validate_nuclio_version_compatibility("1.14.0"):
552
+ raise mlrun.errors.MLRunValueError(
553
+ "Batching is only supported on Nuclio 1.14.0 and higher"
554
+ )
555
+ trigger._struct["batch"] = batching_config
556
+
557
+ if async_spec:
558
+ if not validate_nuclio_version_compatibility("1.15.3"):
559
+ raise mlrun.errors.MLRunValueError(
560
+ "Async spec is only supported on Nuclio 1.15.3 and higher"
561
+ )
562
+ if async_spec.enabled:
563
+ trigger._struct["mode"] = "async"
564
+ trigger._struct["async"] = {
565
+ "maxConnectionsNumber": async_spec.max_connections,
566
+ "connectionAvailabilityTimeout": async_spec.connection_availability_timeout,
567
+ }
568
+
520
569
  self.add_trigger(trigger_name or "http", trigger)
521
570
  return self
522
571
 
@@ -827,21 +876,6 @@ class RemoteRuntime(KubeResource):
827
876
  raise ValueError("function or deploy process not found")
828
877
  return self.status.state, text, last_log_timestamp
829
878
 
830
- def _get_runtime_env(self):
831
- # for runtime specific env var enrichment (before deploy)
832
- runtime_env = {
833
- "MLRUN_ACTIVE_PROJECT": self.metadata.project or mlconf.active_project,
834
- }
835
- if mlconf.httpdb.api_url:
836
- runtime_env["MLRUN_DBPATH"] = mlconf.httpdb.api_url
837
- if mlconf.namespace:
838
- runtime_env["MLRUN_NAMESPACE"] = mlconf.namespace
839
- if self.metadata.credentials.access_key:
840
- runtime_env[
841
- mlrun.common.runtimes.constants.FunctionEnvironmentVariables.auth_session
842
- ] = self.metadata.credentials.access_key
843
- return runtime_env
844
-
845
879
  def _get_serving_spec(self):
846
880
  return None
847
881
 
@@ -866,8 +900,9 @@ class RemoteRuntime(KubeResource):
866
900
  if value_from is not None:
867
901
  external_source_env_dict[sanitized_env_var.get("name")] = value_from
868
902
 
869
- for key, value in self._get_runtime_env().items():
870
- env_dict[key] = value
903
+ envs, external_source_envs = self._generate_runtime_env()
904
+ env_dict.update(envs)
905
+ external_source_env_dict.update(external_source_envs)
871
906
 
872
907
  return env_dict, external_source_env_dict
873
908
 
@@ -924,7 +959,7 @@ class RemoteRuntime(KubeResource):
924
959
  def invoke(
925
960
  self,
926
961
  path: str,
927
- body: typing.Optional[typing.Union[str, bytes, dict]] = None,
962
+ body: typing.Optional[typing.Union[str, bytes, dict, list]] = None,
928
963
  method: typing.Optional[str] = None,
929
964
  headers: typing.Optional[dict] = None,
930
965
  force_external_address: bool = False,
@@ -966,24 +1001,6 @@ class RemoteRuntime(KubeResource):
966
1001
  self._mock_server = None
967
1002
 
968
1003
  if "://" not in path:
969
- if not self.status.address:
970
- # here we check that if default http trigger is disabled, function contains a custom http trigger
971
- # Otherwise, the function is not invokable, so we raise an error
972
- if (
973
- not self._trigger_of_kind_exists(kind="http")
974
- and self.spec.disable_default_http_trigger
975
- ):
976
- raise mlrun.errors.MLRunPreconditionFailedError(
977
- "Default http trigger creation is disabled and there is no any other custom http trigger, "
978
- "so function can not be invoked via http. Either enable default http trigger creation or "
979
- "create custom http trigger"
980
- )
981
- state, _, _ = self._get_state()
982
- if state not in ["ready", "scaledToZero"]:
983
- logger.warning(f"Function is in the {state} state")
984
- if not self.status.address:
985
- raise ValueError("no function address first run .deploy()")
986
-
987
1004
  path = self._resolve_invocation_url(path, force_external_address)
988
1005
 
989
1006
  if headers is None:
@@ -997,7 +1014,7 @@ class RemoteRuntime(KubeResource):
997
1014
  if not http_client_kwargs:
998
1015
  http_client_kwargs = {}
999
1016
  if body:
1000
- if isinstance(body, (str, bytes)):
1017
+ if isinstance(body, str | bytes):
1001
1018
  http_client_kwargs["data"] = body
1002
1019
  else:
1003
1020
  http_client_kwargs["json"] = body
@@ -1043,6 +1060,9 @@ class RemoteRuntime(KubeResource):
1043
1060
  sidecar["image"] = image
1044
1061
 
1045
1062
  ports = mlrun.utils.helpers.as_list(ports)
1063
+ if len(ports) > 1:
1064
+ mlrun.runtimes.nuclio.multiple_port_sidecar_is_supported()
1065
+
1046
1066
  # according to RFC-6335, port name should be less than 15 characters,
1047
1067
  # so we truncate it if needed and leave room for the index
1048
1068
  port_name = name[:13].rstrip("-_") if len(name) > 13 else name
@@ -1068,6 +1088,20 @@ class RemoteRuntime(KubeResource):
1068
1088
  sidecar["resources"] = self.spec.resources
1069
1089
  self.spec.resources = None
1070
1090
 
1091
+ def set_probe(self, *args, **kwargs):
1092
+ """Set a Kubernetes probe configuration for the sidecar container
1093
+
1094
+ This method is only available for ApplicationRuntime.
1095
+ """
1096
+ raise ValueError("set_probe() is only supported for ApplicationRuntime. ")
1097
+
1098
+ def delete_probe(self, *args, **kwargs):
1099
+ """Delete a Kubernetes probe configuration from the sidecar container
1100
+
1101
+ This method is only available for ApplicationRuntime.
1102
+ """
1103
+ raise ValueError("delete_probe() is only supported for ApplicationRuntime.")
1104
+
1071
1105
  def _set_sidecar(self, name: str) -> dict:
1072
1106
  self.spec.config.setdefault("spec.sidecars", [])
1073
1107
  sidecars = self.spec.config["spec.sidecars"]
@@ -1078,6 +1112,79 @@ class RemoteRuntime(KubeResource):
1078
1112
  sidecars.append({"name": name})
1079
1113
  return sidecars[-1]
1080
1114
 
1115
+ def _mask_trigger_config(self, trigger_name, trigger_config):
1116
+ self._mask_rabbitmq_url(trigger=trigger_config)
1117
+ for path in SENSITIVE_PATHS_IN_TRIGGER_CONFIG:
1118
+ # Handle nested keys
1119
+ nested_keys = path.split("/")
1120
+ target = trigger_config
1121
+ for sub_key in nested_keys[:-1]:
1122
+ target = target.get(sub_key, {})
1123
+
1124
+ last_key = nested_keys[-1]
1125
+ if last_key in target:
1126
+ sensitive_field = target[last_key]
1127
+ if sensitive_field.startswith(
1128
+ mlrun.model.Credentials.secret_reference_prefix
1129
+ ):
1130
+ # already masked
1131
+ continue
1132
+ target[last_key] = (
1133
+ f"{mlrun.model.Credentials.secret_reference_prefix}/spec/triggers/{trigger_name}/{path}"
1134
+ )
1135
+
1136
+ @staticmethod
1137
+ def _mask_rabbitmq_url(trigger):
1138
+ """
1139
+ Extract credentials from RabbitMQ URL and move them to attributes dict.
1140
+ This ensures credentials are not exposed in the URL.
1141
+ """
1142
+
1143
+ # supported only for nuclio higher than 1.14.15
1144
+ if not validate_nuclio_version_compatibility("1.14.15"):
1145
+ return
1146
+ if not isinstance(trigger, dict):
1147
+ return
1148
+
1149
+ if trigger.get("kind") != "rabbit-mq":
1150
+ return
1151
+
1152
+ url = trigger.get("url")
1153
+ if not url or not isinstance(url, str):
1154
+ return
1155
+
1156
+ try:
1157
+ parsed = urlparse(url)
1158
+ except Exception:
1159
+ raise mlrun.errors.MLRunValueError("invalid URL format")
1160
+
1161
+ # Only process if credentials are present in the URL
1162
+ if not (parsed.username or parsed.password):
1163
+ return
1164
+
1165
+ # Extract credentials
1166
+ username = parsed.username or ""
1167
+ password = parsed.password or ""
1168
+
1169
+ # Reconstruct clean URL
1170
+ hostname = parsed.hostname or ""
1171
+ netloc = f"{hostname}:{parsed.port}" if parsed.port else hostname
1172
+
1173
+ clean_url = urlunparse(
1174
+ (
1175
+ parsed.scheme,
1176
+ netloc,
1177
+ parsed.path,
1178
+ parsed.params,
1179
+ parsed.query,
1180
+ parsed.fragment,
1181
+ )
1182
+ )
1183
+
1184
+ # Update trigger safely
1185
+ trigger["url"] = clean_url
1186
+ trigger.update({"username": username, "password": password})
1187
+
1081
1188
  def _trigger_of_kind_exists(self, kind: str) -> bool:
1082
1189
  if not self.spec.config:
1083
1190
  return False
@@ -1223,19 +1330,54 @@ class RemoteRuntime(KubeResource):
1223
1330
  # internal / external invocation urls is a nuclio >= 1.6.x feature
1224
1331
  # try to infer the invocation url from the internal and if not exists, use external.
1225
1332
  # $$$$ we do not want to use the external invocation url (e.g.: ingress, nodePort, etc.)
1333
+
1334
+ # if none of urls is set, function was deployed with watch=False
1335
+ # and status wasn't fetched with Nuclio
1336
+ # _get_state fetches the state and updates url
1337
+ if (
1338
+ not self.status.address
1339
+ and not self.status.internal_invocation_urls
1340
+ and not self.status.external_invocation_urls
1341
+ ):
1342
+ state, _, _ = self._get_state()
1343
+ if state not in ["ready", "scaledToZero"]:
1344
+ logger.warning(f"Function is in the {state} state")
1345
+
1346
+ # prefer internal invocation url if running inside k8s cluster
1226
1347
  if (
1227
1348
  not force_external_address
1228
1349
  and self.status.internal_invocation_urls
1229
1350
  and mlrun.k8s_utils.is_running_inside_kubernetes_cluster()
1230
1351
  ):
1231
- return mlrun.utils.helpers.join_urls(
1352
+ url = mlrun.utils.helpers.join_urls(
1232
1353
  f"http://{self.status.internal_invocation_urls[0]}", path
1233
1354
  )
1355
+ logger.debug(
1356
+ f"Using internal invocation url {url}. Make sure you have network access to the k8s cluster. "
1357
+ f"Otherwise, set force_external_address to True"
1358
+ )
1359
+ return url
1234
1360
 
1235
1361
  if self.status.external_invocation_urls:
1236
1362
  return mlrun.utils.helpers.join_urls(
1237
1363
  f"http://{self.status.external_invocation_urls[0]}", path
1238
1364
  )
1365
+
1366
+ if not self.status.address:
1367
+ # if there is no address
1368
+ # here we check that if default http trigger is disabled, function contains a custom http trigger
1369
+ # Otherwise, the function is not invokable, so we raise an error
1370
+ if (
1371
+ not self._trigger_of_kind_exists(kind="http")
1372
+ and self.spec.disable_default_http_trigger
1373
+ ):
1374
+ raise mlrun.errors.MLRunPreconditionFailedError(
1375
+ "Default http trigger creation is disabled and there is no any other custom http trigger, "
1376
+ "so function can not be invoked via http. Either enable default http trigger creation or "
1377
+ "create custom http trigger"
1378
+ )
1379
+ else:
1380
+ raise ValueError("no function address first run .deploy()")
1239
1381
  else:
1240
1382
  return mlrun.utils.helpers.join_urls(f"http://{self.status.address}", path)
1241
1383
 
@@ -1289,6 +1431,8 @@ class RemoteRuntime(KubeResource):
1289
1431
  def get_url(
1290
1432
  self,
1291
1433
  force_external_address: bool = False,
1434
+ # leaving auth_info for BC
1435
+ # TODO: remove in 1.12.0
1292
1436
  auth_info: AuthInfo = None,
1293
1437
  ):
1294
1438
  """
@@ -1299,13 +1443,12 @@ class RemoteRuntime(KubeResource):
1299
1443
 
1300
1444
  :return: returns function's url
1301
1445
  """
1302
- if not self.status.address:
1303
- state, _, _ = self._get_state(auth_info=auth_info)
1304
- if state != "ready" or not self.status.address:
1305
- raise ValueError(
1306
- "no function address or not ready, first run .deploy()"
1307
- )
1308
-
1446
+ if auth_info:
1447
+ warnings.warn(
1448
+ "'auth_info' is deprecated in 1.10.0 and will be removed in 1.12.0.",
1449
+ # TODO: Remove this in 1.12.0
1450
+ FutureWarning,
1451
+ )
1309
1452
  return self._resolve_invocation_url("", force_external_address)
1310
1453
 
1311
1454
  @staticmethod
@@ -1418,7 +1561,7 @@ def get_nuclio_deploy_status(
1418
1561
  verbose,
1419
1562
  resolve_address,
1420
1563
  return_function_status=True,
1421
- auth_info=auth_info.to_nuclio_auth_info() if auth_info else None,
1564
+ auth_info=mlrun.auth.nuclio.NuclioAuthInfo.from_auth_info(auth_info),
1422
1565
  )
1423
1566
  except requests.exceptions.ConnectionError as exc:
1424
1567
  mlrun.errors.raise_for_status(
@@ -1456,3 +1599,10 @@ def enrich_nuclio_function_from_headers(
1456
1599
  else []
1457
1600
  )
1458
1601
  func.status.container_image = headers.get("x-mlrun-container-image", "")
1602
+
1603
+
1604
+ @min_nuclio_versions("1.14.14")
1605
+ def multiple_port_sidecar_is_supported():
1606
+ # multiple ports are supported from nuclio version 1.14.14
1607
+ # this method exists only for running the min_nuclio_versions decorator
1608
+ return True