mlrun 1.10.0rc16__py3-none-any.whl → 1.10.0rc42__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 (98) hide show
  1. mlrun/__init__.py +22 -2
  2. mlrun/artifacts/document.py +6 -1
  3. mlrun/artifacts/llm_prompt.py +21 -15
  4. mlrun/artifacts/model.py +3 -3
  5. mlrun/common/constants.py +9 -0
  6. mlrun/common/formatters/artifact.py +1 -0
  7. mlrun/common/model_monitoring/helpers.py +86 -0
  8. mlrun/common/schemas/__init__.py +2 -0
  9. mlrun/common/schemas/auth.py +2 -0
  10. mlrun/common/schemas/function.py +10 -0
  11. mlrun/common/schemas/hub.py +30 -18
  12. mlrun/common/schemas/model_monitoring/__init__.py +2 -0
  13. mlrun/common/schemas/model_monitoring/constants.py +30 -6
  14. mlrun/common/schemas/model_monitoring/functions.py +13 -4
  15. mlrun/common/schemas/model_monitoring/model_endpoints.py +11 -0
  16. mlrun/common/schemas/pipeline.py +1 -1
  17. mlrun/common/schemas/serving.py +3 -0
  18. mlrun/common/schemas/workflow.py +1 -0
  19. mlrun/common/secrets.py +22 -1
  20. mlrun/config.py +32 -10
  21. mlrun/datastore/__init__.py +11 -3
  22. mlrun/datastore/azure_blob.py +162 -47
  23. mlrun/datastore/datastore.py +9 -4
  24. mlrun/datastore/datastore_profile.py +61 -5
  25. mlrun/datastore/model_provider/huggingface_provider.py +363 -0
  26. mlrun/datastore/model_provider/mock_model_provider.py +87 -0
  27. mlrun/datastore/model_provider/model_provider.py +211 -74
  28. mlrun/datastore/model_provider/openai_provider.py +243 -71
  29. mlrun/datastore/s3.py +24 -2
  30. mlrun/datastore/storeytargets.py +2 -3
  31. mlrun/datastore/utils.py +15 -3
  32. mlrun/db/base.py +27 -19
  33. mlrun/db/httpdb.py +57 -48
  34. mlrun/db/nopdb.py +25 -10
  35. mlrun/execution.py +55 -13
  36. mlrun/hub/__init__.py +15 -0
  37. mlrun/hub/module.py +181 -0
  38. mlrun/k8s_utils.py +105 -16
  39. mlrun/launcher/base.py +13 -6
  40. mlrun/launcher/local.py +2 -0
  41. mlrun/model.py +9 -3
  42. mlrun/model_monitoring/api.py +66 -27
  43. mlrun/model_monitoring/applications/__init__.py +1 -1
  44. mlrun/model_monitoring/applications/base.py +372 -136
  45. mlrun/model_monitoring/applications/context.py +2 -4
  46. mlrun/model_monitoring/applications/results.py +4 -7
  47. mlrun/model_monitoring/controller.py +239 -101
  48. mlrun/model_monitoring/db/_schedules.py +36 -13
  49. mlrun/model_monitoring/db/_stats.py +4 -3
  50. mlrun/model_monitoring/db/tsdb/base.py +29 -9
  51. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +4 -5
  52. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +154 -50
  53. mlrun/model_monitoring/db/tsdb/tdengine/writer_graph_steps.py +51 -0
  54. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +17 -4
  55. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +245 -51
  56. mlrun/model_monitoring/helpers.py +28 -5
  57. mlrun/model_monitoring/stream_processing.py +45 -14
  58. mlrun/model_monitoring/writer.py +220 -1
  59. mlrun/platforms/__init__.py +3 -2
  60. mlrun/platforms/iguazio.py +7 -3
  61. mlrun/projects/operations.py +6 -1
  62. mlrun/projects/pipelines.py +2 -2
  63. mlrun/projects/project.py +128 -45
  64. mlrun/run.py +94 -17
  65. mlrun/runtimes/__init__.py +18 -0
  66. mlrun/runtimes/base.py +14 -6
  67. mlrun/runtimes/daskjob.py +1 -0
  68. mlrun/runtimes/local.py +5 -2
  69. mlrun/runtimes/mounts.py +20 -2
  70. mlrun/runtimes/nuclio/__init__.py +1 -0
  71. mlrun/runtimes/nuclio/application/application.py +147 -17
  72. mlrun/runtimes/nuclio/function.py +70 -27
  73. mlrun/runtimes/nuclio/serving.py +85 -4
  74. mlrun/runtimes/pod.py +213 -21
  75. mlrun/runtimes/utils.py +49 -9
  76. mlrun/secrets.py +54 -13
  77. mlrun/serving/remote.py +79 -6
  78. mlrun/serving/routers.py +23 -41
  79. mlrun/serving/server.py +211 -40
  80. mlrun/serving/states.py +536 -156
  81. mlrun/serving/steps.py +62 -0
  82. mlrun/serving/system_steps.py +136 -81
  83. mlrun/serving/v2_serving.py +9 -10
  84. mlrun/utils/helpers.py +212 -82
  85. mlrun/utils/logger.py +3 -1
  86. mlrun/utils/notifications/notification/base.py +18 -0
  87. mlrun/utils/notifications/notification/git.py +2 -4
  88. mlrun/utils/notifications/notification/slack.py +2 -4
  89. mlrun/utils/notifications/notification/webhook.py +2 -5
  90. mlrun/utils/notifications/notification_pusher.py +1 -1
  91. mlrun/utils/version/version.json +2 -2
  92. {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/METADATA +44 -45
  93. {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/RECORD +97 -92
  94. mlrun/api/schemas/__init__.py +0 -259
  95. {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/WHEEL +0 -0
  96. {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/entry_points.txt +0 -0
  97. {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/licenses/LICENSE +0 -0
  98. {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/top_level.txt +0 -0
mlrun/runtimes/base.py CHANGED
@@ -142,9 +142,6 @@ class FunctionSpec(ModelObj):
142
142
  def build(self, build):
143
143
  self._build = self._verify_dict(build, "build", ImageBuilder)
144
144
 
145
- def enrich_function_preemption_spec(self):
146
- pass
147
-
148
145
  def validate_service_account(self, allowed_service_accounts):
149
146
  pass
150
147
 
@@ -379,7 +376,12 @@ class BaseRuntime(ModelObj):
379
376
  This ensures latest code changes are executed. This argument must be used in
380
377
  conjunction with the local=True argument.
381
378
  :param output_path: Default artifact output path.
382
- :param retry: Retry configuration for the run, can be a dict or an instance of mlrun.model.Retry.
379
+ :param retry: Retry configuration for the run, can be a dict or an instance of
380
+ :py:class:`~mlrun.model.Retry`.
381
+ The `count` field in the `Retry` object specifies the number of retry attempts.
382
+ If `count=0`, the run will not be retried.
383
+ The `backoff` field specifies the retry backoff strategy between retry attempts.
384
+ If not provided, the default backoff delay is 30 seconds.
383
385
  :return: Run context object (RunObject) with run metadata, results and status
384
386
  """
385
387
  if artifact_path or out_path:
@@ -391,6 +393,7 @@ class BaseRuntime(ModelObj):
391
393
  FutureWarning,
392
394
  )
393
395
  output_path = output_path or out_path or artifact_path
396
+
394
397
  launcher = mlrun.launcher.factory.LauncherFactory().create_launcher(
395
398
  self._is_remote, local=local, **launcher_kwargs
396
399
  )
@@ -446,15 +449,20 @@ class BaseRuntime(ModelObj):
446
449
  :param runobj: Run context object (RunObject) with run metadata and status
447
450
  :return: Dictionary with all the variables that could be parsed
448
451
  """
452
+ active_project = self.metadata.project or config.active_project
449
453
  runtime_env = {
450
- "MLRUN_ACTIVE_PROJECT": self.metadata.project or config.active_project
454
+ mlrun_constants.MLRUN_ACTIVE_PROJECT: active_project,
455
+ # TODO: Remove this in 1.12.0 as MLRUN_DEFAULT_PROJECT is deprecated and should not be injected anymore
456
+ "MLRUN_DEFAULT_PROJECT": active_project,
451
457
  }
452
458
  if runobj:
453
459
  runtime_env["MLRUN_EXEC_CONFIG"] = runobj.to_json(
454
460
  exclude_notifications_params=True
455
461
  )
456
462
  if runobj.metadata.project:
457
- runtime_env["MLRUN_ACTIVE_PROJECT"] = runobj.metadata.project
463
+ runtime_env[mlrun_constants.MLRUN_ACTIVE_PROJECT] = (
464
+ runobj.metadata.project
465
+ )
458
466
  if runobj.spec.verbose:
459
467
  runtime_env["MLRUN_LOG_LEVEL"] = "DEBUG"
460
468
  if config.httpdb.api_url:
mlrun/runtimes/daskjob.py CHANGED
@@ -541,6 +541,7 @@ class DaskCluster(KubejobRuntime):
541
541
  notifications=notifications,
542
542
  returns=returns,
543
543
  state_thresholds=state_thresholds,
544
+ retry=retry,
544
545
  **launcher_kwargs,
545
546
  )
546
547
 
mlrun/runtimes/local.py CHANGED
@@ -29,12 +29,12 @@ from os import environ, remove
29
29
  from pathlib import Path
30
30
  from subprocess import PIPE, Popen
31
31
  from sys import executable
32
+ from typing import Optional
32
33
 
33
34
  from nuclio import Event
34
35
 
35
36
  import mlrun
36
37
  import mlrun.common.constants as mlrun_constants
37
- import mlrun.common.runtimes.constants
38
38
  from mlrun.lists import RunList
39
39
 
40
40
  from ..errors import err_to_str
@@ -201,9 +201,12 @@ class LocalRuntime(BaseRuntime, ParallelRunner):
201
201
  kind = "local"
202
202
  _is_remote = False
203
203
 
204
- def to_job(self, image=""):
204
+ def to_job(self, image="", func_name: Optional[str] = None):
205
205
  struct = self.to_dict()
206
206
  obj = KubejobRuntime.from_dict(struct)
207
+ obj.kind = "job" # Ensure kind is set to 'job' for KubejobRuntime
208
+ if func_name:
209
+ obj.metadata.name = func_name
207
210
  if image:
208
211
  obj.spec.image = image
209
212
  return obj
mlrun/runtimes/mounts.py CHANGED
@@ -14,8 +14,11 @@
14
14
 
15
15
  import os
16
16
  import typing
17
+ import warnings
17
18
  from collections import namedtuple
18
19
 
20
+ import mlrun.common.secrets
21
+ import mlrun.errors
19
22
  from mlrun.config import config
20
23
  from mlrun.config import config as mlconf
21
24
  from mlrun.errors import MLRunInvalidArgumentError
@@ -247,10 +250,22 @@ def mount_s3(
247
250
  def _use_s3_cred(runtime: "KubeResource"):
248
251
  _access_key = aws_access_key or os.environ.get(prefix + "AWS_ACCESS_KEY_ID")
249
252
  _secret_key = aws_secret_key or os.environ.get(prefix + "AWS_SECRET_ACCESS_KEY")
250
- _endpoint_url = endpoint_url or os.environ.get(prefix + "S3_ENDPOINT_URL")
253
+
254
+ # Check for endpoint URL with backward compatibility
255
+ _endpoint_url = endpoint_url or os.environ.get(prefix + "AWS_ENDPOINT_URL_S3")
256
+ if not _endpoint_url:
257
+ # Check for deprecated environment variable
258
+ _endpoint_url = os.environ.get(prefix + "S3_ENDPOINT_URL")
259
+ if _endpoint_url:
260
+ warnings.warn(
261
+ "S3_ENDPOINT_URL is deprecated in 1.10.0 and will be removed in 1.12.0, "
262
+ "use AWS_ENDPOINT_URL_S3 instead.",
263
+ # TODO: Remove this in 1.12.0
264
+ FutureWarning,
265
+ )
251
266
 
252
267
  if _endpoint_url:
253
- runtime.set_env(prefix + "S3_ENDPOINT_URL", _endpoint_url)
268
+ runtime.set_env(prefix + "AWS_ENDPOINT_URL_S3", _endpoint_url)
254
269
  if aws_region:
255
270
  runtime.set_env(prefix + "AWS_REGION", aws_region)
256
271
  if non_anonymous:
@@ -399,6 +414,9 @@ def mount_secret(
399
414
  the specified paths, and unlisted keys will not be
400
415
  present."""
401
416
 
417
+ if secret_name:
418
+ mlrun.common.secrets.validate_not_forbidden_secret(secret_name.strip())
419
+
402
420
  def _mount_secret(runtime: "KubeResource"):
403
421
  # Define the secret volume source
404
422
  secret_volume_source = {
@@ -16,6 +16,7 @@ from .serving import ServingRuntime, new_v2_model_server # noqa
16
16
  from .nuclio import nuclio_init_hook # noqa
17
17
  from .function import (
18
18
  min_nuclio_versions,
19
+ multiple_port_sidecar_is_supported,
19
20
  RemoteRuntime,
20
21
  ) # noqa
21
22
  from .api_gateway import APIGateway
@@ -22,19 +22,23 @@ import mlrun.errors
22
22
  import mlrun.run
23
23
  from mlrun.common.runtimes.constants import NuclioIngressAddTemplatedIngressModes
24
24
  from mlrun.runtimes import RemoteRuntime
25
- from mlrun.runtimes.nuclio import min_nuclio_versions
25
+ from mlrun.runtimes.nuclio import (
26
+ min_nuclio_versions,
27
+ multiple_port_sidecar_is_supported,
28
+ )
26
29
  from mlrun.runtimes.nuclio.api_gateway import (
27
30
  APIGateway,
28
31
  APIGatewayMetadata,
29
32
  APIGatewaySpec,
30
33
  )
31
34
  from mlrun.runtimes.nuclio.function import NuclioSpec, NuclioStatus
32
- from mlrun.utils import logger, update_in
35
+ from mlrun.utils import is_valid_port, logger, update_in
33
36
 
34
37
 
35
38
  class ApplicationSpec(NuclioSpec):
36
39
  _dict_fields = NuclioSpec._dict_fields + [
37
40
  "internal_application_port",
41
+ "application_ports",
38
42
  ]
39
43
 
40
44
  def __init__(
@@ -78,7 +82,12 @@ class ApplicationSpec(NuclioSpec):
78
82
  add_templated_ingress_host_mode=None,
79
83
  state_thresholds=None,
80
84
  disable_default_http_trigger=None,
85
+ serving_spec=None,
86
+ graph=None,
87
+ parameters=None,
88
+ track_models=None,
81
89
  internal_application_port=None,
90
+ application_ports=None,
82
91
  ):
83
92
  super().__init__(
84
93
  command=command,
@@ -118,6 +127,10 @@ class ApplicationSpec(NuclioSpec):
118
127
  security_context=security_context,
119
128
  service_type=service_type,
120
129
  add_templated_ingress_host_mode=add_templated_ingress_host_mode,
130
+ serving_spec=serving_spec,
131
+ graph=graph,
132
+ parameters=parameters,
133
+ track_models=track_models,
121
134
  state_thresholds=state_thresholds,
122
135
  disable_default_http_trigger=disable_default_http_trigger,
123
136
  )
@@ -126,11 +139,60 @@ class ApplicationSpec(NuclioSpec):
126
139
  self.min_replicas = min_replicas or 1
127
140
  self.max_replicas = max_replicas or 1
128
141
 
142
+ # initializing internal application port and application ports
143
+ self._internal_application_port = None
144
+ self._application_ports = []
145
+
146
+ application_ports = application_ports or []
147
+
148
+ # if internal_application_port is not provided, use the first application port
149
+ if not internal_application_port and len(application_ports) > 0:
150
+ internal_application_port = application_ports[0]
151
+
152
+ # the port of application sidecar to which traffic will be routed from a nuclio function
129
153
  self.internal_application_port = (
130
154
  internal_application_port
131
155
  or mlrun.mlconf.function.application.default_sidecar_internal_port
132
156
  )
133
157
 
158
+ # all exposed ports by the application sidecar
159
+ self.application_ports = application_ports
160
+
161
+ @property
162
+ def application_ports(self):
163
+ return self._application_ports
164
+
165
+ @application_ports.setter
166
+ def application_ports(self, ports):
167
+ """
168
+ Set the application ports for the application sidecar.
169
+ The internal application port is always included and always first.
170
+ """
171
+ # Handle None / single int
172
+ if ports is None:
173
+ ports = []
174
+ elif isinstance(ports, int):
175
+ ports = [ports]
176
+ elif not isinstance(ports, list):
177
+ raise mlrun.errors.MLRunInvalidArgumentError(
178
+ "Application ports must be a list of integers"
179
+ )
180
+
181
+ # Validate and normalize
182
+ cleaned_ports = []
183
+ for port in ports:
184
+ is_valid_port(port, raise_on_error=True)
185
+ if port != self.internal_application_port:
186
+ cleaned_ports.append(port)
187
+
188
+ application_ports = [self.internal_application_port] + cleaned_ports
189
+
190
+ # ensure multiple ports are supported in Nuclio
191
+ if len(application_ports) > 1:
192
+ multiple_port_sidecar_is_supported()
193
+
194
+ self._application_ports = application_ports
195
+
134
196
  @property
135
197
  def internal_application_port(self):
136
198
  return self._internal_application_port
@@ -138,10 +200,20 @@ class ApplicationSpec(NuclioSpec):
138
200
  @internal_application_port.setter
139
201
  def internal_application_port(self, port):
140
202
  port = int(port)
141
- if port < 0 or port > 65535:
142
- raise ValueError("Port must be in the range 0-65535")
203
+ is_valid_port(port, raise_on_error=True)
143
204
  self._internal_application_port = port
144
205
 
206
+ # If when internal application port is being set, length of self._application_ports is 1,
207
+ # it means that it consist of [old_port] only
208
+ # so in this case, we rewrite the list completely, by setting value to [new_value]
209
+ if len(self.application_ports) == 1:
210
+ self._application_ports = [port]
211
+ return
212
+
213
+ # when setting new internal application port, ensure that it is included in the application ports
214
+ # it just triggers setter logic, so setting to the same value is a no-op
215
+ self.application_ports = self._application_ports
216
+
145
217
 
146
218
  class ApplicationStatus(NuclioStatus):
147
219
  def __init__(
@@ -222,6 +294,32 @@ class ApplicationRuntime(RemoteRuntime):
222
294
  def set_internal_application_port(self, port: int):
223
295
  self.spec.internal_application_port = port
224
296
 
297
+ def with_sidecar(
298
+ self,
299
+ name: typing.Optional[str] = None,
300
+ image: typing.Optional[str] = None,
301
+ ports: typing.Optional[typing.Union[int, list[int]]] = None,
302
+ command: typing.Optional[str] = None,
303
+ args: typing.Optional[list[str]] = None,
304
+ ):
305
+ # wraps with_sidecar just to set the application ports
306
+ super().with_sidecar(
307
+ name=name,
308
+ image=image,
309
+ ports=ports,
310
+ command=command,
311
+ args=args,
312
+ )
313
+
314
+ if ports:
315
+ if self.spec.internal_application_port != ports[0]:
316
+ logger.info(
317
+ f"Setting internal application port to the first port from the sidecar: {ports[0]}. "
318
+ f"If this is not intended, please set the internal_application_port explicitly."
319
+ )
320
+ self.spec.internal_application_port = ports[0]
321
+ self.spec.application_ports = ports
322
+
225
323
  def pre_deploy_validation(self):
226
324
  super().pre_deploy_validation()
227
325
  if not self.spec.config.get("spec.sidecars"):
@@ -302,6 +400,7 @@ class ApplicationRuntime(RemoteRuntime):
302
400
 
303
401
  :return: The default API gateway URL if created or True if the function is ready (deployed)
304
402
  """
403
+
305
404
  if (self.requires_build() and not self.spec.image) or force_build:
306
405
  self._fill_credentials()
307
406
  self._build_application_image(
@@ -315,8 +414,7 @@ class ApplicationRuntime(RemoteRuntime):
315
414
  show_on_failure=show_on_failure,
316
415
  )
317
416
 
318
- # This is a class method that accepts a function instance, so we pass self as the function instance
319
- self._ensure_reverse_proxy_configurations(self)
417
+ self._ensure_reverse_proxy_configurations()
320
418
  self._configure_application_sidecar()
321
419
 
322
420
  # We only allow accessing the application via the API Gateway
@@ -431,6 +529,7 @@ class ApplicationRuntime(RemoteRuntime):
431
529
  ssl_redirect: typing.Optional[bool] = None,
432
530
  set_as_default: bool = False,
433
531
  gateway_timeout: typing.Optional[int] = None,
532
+ port: typing.Optional[int] = None,
434
533
  ):
435
534
  """
436
535
  Create the application API gateway. Once the application is deployed, the API gateway can be created.
@@ -447,6 +546,8 @@ class ApplicationRuntime(RemoteRuntime):
447
546
  :param set_as_default: Set the API gateway as the default for the application (`status.api_gateway`)
448
547
  :param gateway_timeout: nginx ingress timeout in sec (request timeout, when will the gateway return an
449
548
  error)
549
+ :param port: The API gateway port, used only when direct_port_access=True
550
+
450
551
  :return: The API gateway URL
451
552
  """
452
553
  if not name:
@@ -467,7 +568,15 @@ class ApplicationRuntime(RemoteRuntime):
467
568
  "Authentication credentials not provided"
468
569
  )
469
570
 
470
- ports = self.spec.internal_application_port if direct_port_access else []
571
+ if direct_port_access and port:
572
+ logger.warning(
573
+ "Ignoring 'port' because 'direct_port_access' is enabled. "
574
+ "The 'port' setting is only applicable when 'direct_port_access' is disabled."
575
+ )
576
+
577
+ ports = (
578
+ port or self.spec.internal_application_port if direct_port_access else []
579
+ )
471
580
 
472
581
  api_gateway = APIGateway(
473
582
  APIGatewayMetadata(
@@ -595,6 +704,12 @@ class ApplicationRuntime(RemoteRuntime):
595
704
  """
596
705
  # create a function that includes only the reverse proxy, without the application
597
706
 
707
+ if not mlrun.get_current_project(silent=True):
708
+ raise mlrun.errors.MLRunMissingProjectError(
709
+ "An active project is required to run deploy_reverse_proxy_image(). "
710
+ "Use `mlrun.get_or_create_project()` or set an active project first."
711
+ )
712
+
598
713
  reverse_proxy_func = mlrun.run.new_function(
599
714
  name="reverse-proxy-temp", kind="remote"
600
715
  )
@@ -684,27 +799,42 @@ class ApplicationRuntime(RemoteRuntime):
684
799
  with_mlrun=with_mlrun,
685
800
  )
686
801
 
687
- @staticmethod
688
- def _ensure_reverse_proxy_configurations(function: RemoteRuntime):
689
- if function.spec.build.functionSourceCode or function.status.container_image:
802
+ def _ensure_reverse_proxy_configurations(self):
803
+ # If an HTTP trigger already exists in the spec,
804
+ # it means the user explicitly defined a custom configuration,
805
+ # so, skip automatic creation.
806
+ skip_http_trigger_creation = False
807
+ for key, value in self.spec.config.items():
808
+ if key.startswith("spec.triggers"):
809
+ if isinstance(value, dict):
810
+ if value.get("kind") == "http":
811
+ skip_http_trigger_creation = True
812
+ break
813
+ if not skip_http_trigger_creation:
814
+ self.with_http(
815
+ workers=mlrun.mlconf.function.application.default_worker_number,
816
+ trigger_name="application-http",
817
+ )
818
+
819
+ if self.spec.build.functionSourceCode or self.status.container_image:
690
820
  return
691
821
 
692
822
  filename, handler = ApplicationRuntime.get_filename_and_handler()
693
823
  name, spec, code = nuclio.build_file(
694
824
  filename,
695
- name=function.metadata.name,
825
+ name=self.metadata.name,
696
826
  handler=handler,
697
827
  )
698
- function.spec.function_handler = mlrun.utils.get_in(spec, "spec.handler")
699
- function.spec.build.functionSourceCode = mlrun.utils.get_in(
828
+ self.spec.function_handler = mlrun.utils.get_in(spec, "spec.handler")
829
+ self.spec.build.functionSourceCode = mlrun.utils.get_in(
700
830
  spec, "spec.build.functionSourceCode"
701
831
  )
702
- function.spec.nuclio_runtime = mlrun.utils.get_in(spec, "spec.runtime")
832
+ self.spec.nuclio_runtime = mlrun.utils.get_in(spec, "spec.runtime")
703
833
 
704
834
  # default the reverse proxy logger level to info
705
835
  logger_sinks_key = "spec.loggerSinks"
706
- if not function.spec.config.get(logger_sinks_key):
707
- function.set_config(
836
+ if not self.spec.config.get(logger_sinks_key):
837
+ self.set_config(
708
838
  logger_sinks_key, [{"level": "info", "sink": "myStdoutLoggerSink"}]
709
839
  )
710
840
 
@@ -728,7 +858,7 @@ class ApplicationRuntime(RemoteRuntime):
728
858
  self.with_sidecar(
729
859
  name=self.status.sidecar_name,
730
860
  image=self.status.application_image,
731
- ports=self.spec.internal_application_port,
861
+ ports=self.spec.application_ports,
732
862
  command=self.spec.command,
733
863
  args=self.spec.args,
734
864
  )
@@ -16,6 +16,7 @@ import asyncio
16
16
  import copy
17
17
  import json
18
18
  import typing
19
+ import warnings
19
20
  from datetime import datetime
20
21
  from time import sleep
21
22
 
@@ -29,6 +30,7 @@ from kubernetes import client
29
30
  from nuclio.deploy import find_dashboard_url, get_deploy_status
30
31
  from nuclio.triggers import V3IOStreamTrigger
31
32
 
33
+ import mlrun.common.constants
32
34
  import mlrun.db
33
35
  import mlrun.errors
34
36
  import mlrun.k8s_utils
@@ -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
@@ -830,7 +844,8 @@ class RemoteRuntime(KubeResource):
830
844
  def _get_runtime_env(self):
831
845
  # for runtime specific env var enrichment (before deploy)
832
846
  runtime_env = {
833
- "MLRUN_ACTIVE_PROJECT": self.metadata.project or mlconf.active_project,
847
+ mlrun.common.constants.MLRUN_ACTIVE_PROJECT: self.metadata.project
848
+ or mlconf.active_project,
834
849
  }
835
850
  if mlconf.httpdb.api_url:
836
851
  runtime_env["MLRUN_DBPATH"] = mlconf.httpdb.api_url
@@ -966,24 +981,6 @@ class RemoteRuntime(KubeResource):
966
981
  self._mock_server = None
967
982
 
968
983
  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
984
  path = self._resolve_invocation_url(path, force_external_address)
988
985
 
989
986
  if headers is None:
@@ -1043,6 +1040,9 @@ class RemoteRuntime(KubeResource):
1043
1040
  sidecar["image"] = image
1044
1041
 
1045
1042
  ports = mlrun.utils.helpers.as_list(ports)
1043
+ if len(ports) > 1:
1044
+ mlrun.runtimes.nuclio.multiple_port_sidecar_is_supported()
1045
+
1046
1046
  # according to RFC-6335, port name should be less than 15 characters,
1047
1047
  # so we truncate it if needed and leave room for the index
1048
1048
  port_name = name[:13].rstrip("-_") if len(name) > 13 else name
@@ -1223,19 +1223,54 @@ class RemoteRuntime(KubeResource):
1223
1223
  # internal / external invocation urls is a nuclio >= 1.6.x feature
1224
1224
  # try to infer the invocation url from the internal and if not exists, use external.
1225
1225
  # $$$$ we do not want to use the external invocation url (e.g.: ingress, nodePort, etc.)
1226
+
1227
+ # if none of urls is set, function was deployed with watch=False
1228
+ # and status wasn't fetched with Nuclio
1229
+ # _get_state fetches the state and updates url
1230
+ if (
1231
+ not self.status.address
1232
+ and not self.status.internal_invocation_urls
1233
+ and not self.status.external_invocation_urls
1234
+ ):
1235
+ state, _, _ = self._get_state()
1236
+ if state not in ["ready", "scaledToZero"]:
1237
+ logger.warning(f"Function is in the {state} state")
1238
+
1239
+ # prefer internal invocation url if running inside k8s cluster
1226
1240
  if (
1227
1241
  not force_external_address
1228
1242
  and self.status.internal_invocation_urls
1229
1243
  and mlrun.k8s_utils.is_running_inside_kubernetes_cluster()
1230
1244
  ):
1231
- return mlrun.utils.helpers.join_urls(
1245
+ url = mlrun.utils.helpers.join_urls(
1232
1246
  f"http://{self.status.internal_invocation_urls[0]}", path
1233
1247
  )
1248
+ logger.debug(
1249
+ f"Using internal invocation url {url}. Make sure you have network access to the k8s cluster. "
1250
+ f"Otherwise, set force_external_address to True"
1251
+ )
1252
+ return url
1234
1253
 
1235
1254
  if self.status.external_invocation_urls:
1236
1255
  return mlrun.utils.helpers.join_urls(
1237
1256
  f"http://{self.status.external_invocation_urls[0]}", path
1238
1257
  )
1258
+
1259
+ if not self.status.address:
1260
+ # if there is no address
1261
+ # here we check that if default http trigger is disabled, function contains a custom http trigger
1262
+ # Otherwise, the function is not invokable, so we raise an error
1263
+ if (
1264
+ not self._trigger_of_kind_exists(kind="http")
1265
+ and self.spec.disable_default_http_trigger
1266
+ ):
1267
+ raise mlrun.errors.MLRunPreconditionFailedError(
1268
+ "Default http trigger creation is disabled and there is no any other custom http trigger, "
1269
+ "so function can not be invoked via http. Either enable default http trigger creation or "
1270
+ "create custom http trigger"
1271
+ )
1272
+ else:
1273
+ raise ValueError("no function address first run .deploy()")
1239
1274
  else:
1240
1275
  return mlrun.utils.helpers.join_urls(f"http://{self.status.address}", path)
1241
1276
 
@@ -1289,6 +1324,8 @@ class RemoteRuntime(KubeResource):
1289
1324
  def get_url(
1290
1325
  self,
1291
1326
  force_external_address: bool = False,
1327
+ # leaving auth_info for BC
1328
+ # TODO: remove in 1.12.0
1292
1329
  auth_info: AuthInfo = None,
1293
1330
  ):
1294
1331
  """
@@ -1299,13 +1336,12 @@ class RemoteRuntime(KubeResource):
1299
1336
 
1300
1337
  :return: returns function's url
1301
1338
  """
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
-
1339
+ if auth_info:
1340
+ warnings.warn(
1341
+ "'auth_info' is deprecated in 1.10.0 and will be removed in 1.12.0.",
1342
+ # TODO: Remove this in 1.12.0
1343
+ FutureWarning,
1344
+ )
1309
1345
  return self._resolve_invocation_url("", force_external_address)
1310
1346
 
1311
1347
  @staticmethod
@@ -1456,3 +1492,10 @@ def enrich_nuclio_function_from_headers(
1456
1492
  else []
1457
1493
  )
1458
1494
  func.status.container_image = headers.get("x-mlrun-container-image", "")
1495
+
1496
+
1497
+ @min_nuclio_versions("1.14.14")
1498
+ def multiple_port_sidecar_is_supported():
1499
+ # multiple ports are supported from nuclio version 1.14.14
1500
+ # this method exists only for running the min_nuclio_versions decorator
1501
+ return True