mlrun 1.7.0rc7__py3-none-any.whl → 1.7.0rc9__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 (52) hide show
  1. mlrun/__main__.py +2 -0
  2. mlrun/common/schemas/__init__.py +3 -0
  3. mlrun/common/schemas/api_gateway.py +8 -1
  4. mlrun/common/schemas/hub.py +7 -9
  5. mlrun/common/schemas/model_monitoring/constants.py +1 -1
  6. mlrun/common/schemas/pagination.py +26 -0
  7. mlrun/common/schemas/project.py +15 -10
  8. mlrun/config.py +28 -10
  9. mlrun/datastore/__init__.py +3 -7
  10. mlrun/datastore/datastore_profile.py +19 -1
  11. mlrun/datastore/snowflake_utils.py +43 -0
  12. mlrun/datastore/sources.py +9 -26
  13. mlrun/datastore/targets.py +131 -11
  14. mlrun/datastore/utils.py +10 -5
  15. mlrun/db/base.py +44 -0
  16. mlrun/db/httpdb.py +122 -21
  17. mlrun/db/nopdb.py +107 -0
  18. mlrun/feature_store/api.py +3 -2
  19. mlrun/feature_store/retrieval/spark_merger.py +27 -23
  20. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
  21. mlrun/frameworks/tf_keras/mlrun_interface.py +2 -2
  22. mlrun/kfpops.py +2 -5
  23. mlrun/launcher/base.py +1 -1
  24. mlrun/launcher/client.py +2 -2
  25. mlrun/model_monitoring/helpers.py +3 -1
  26. mlrun/projects/pipelines.py +1 -1
  27. mlrun/projects/project.py +32 -21
  28. mlrun/run.py +5 -1
  29. mlrun/runtimes/__init__.py +16 -0
  30. mlrun/runtimes/base.py +4 -1
  31. mlrun/runtimes/kubejob.py +26 -121
  32. mlrun/runtimes/nuclio/api_gateway.py +58 -8
  33. mlrun/runtimes/nuclio/application/application.py +79 -1
  34. mlrun/runtimes/nuclio/application/reverse_proxy.go +9 -1
  35. mlrun/runtimes/nuclio/function.py +11 -8
  36. mlrun/runtimes/nuclio/serving.py +2 -2
  37. mlrun/runtimes/pod.py +145 -0
  38. mlrun/runtimes/utils.py +0 -28
  39. mlrun/serving/remote.py +2 -3
  40. mlrun/serving/routers.py +4 -3
  41. mlrun/serving/server.py +1 -1
  42. mlrun/serving/states.py +6 -9
  43. mlrun/serving/v2_serving.py +4 -3
  44. mlrun/utils/http.py +1 -1
  45. mlrun/utils/retryer.py +1 -0
  46. mlrun/utils/version/version.json +2 -2
  47. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc9.dist-info}/METADATA +15 -15
  48. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc9.dist-info}/RECORD +52 -50
  49. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc9.dist-info}/LICENSE +0 -0
  50. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc9.dist-info}/WHEEL +0 -0
  51. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc9.dist-info}/entry_points.txt +0 -0
  52. {mlrun-1.7.0rc7.dist-info → mlrun-1.7.0rc9.dist-info}/top_level.txt +0 -0
mlrun/projects/project.py CHANGED
@@ -32,7 +32,7 @@ import dotenv
32
32
  import git
33
33
  import git.exc
34
34
  import kfp
35
- import nuclio
35
+ import nuclio.utils
36
36
  import requests
37
37
  import yaml
38
38
 
@@ -129,6 +129,7 @@ def new_project(
129
129
  save: bool = True,
130
130
  overwrite: bool = False,
131
131
  parameters: dict = None,
132
+ default_function_node_selector: dict = None,
132
133
  ) -> "MlrunProject":
133
134
  """Create a new MLRun project, optionally load it from a yaml/zip/git template
134
135
 
@@ -182,6 +183,7 @@ def new_project(
182
183
  :param overwrite: overwrite project using 'cascade' deletion strategy (deletes project resources)
183
184
  if project with name exists
184
185
  :param parameters: key/value pairs to add to the project.spec.params
186
+ :param default_function_node_selector: defines the default node selector for scheduling functions within the project
185
187
 
186
188
  :returns: project object
187
189
  """
@@ -228,6 +230,11 @@ def new_project(
228
230
  project.spec.origin_url = url
229
231
  if description:
230
232
  project.spec.description = description
233
+
234
+ if default_function_node_selector:
235
+ for key, val in default_function_node_selector.items():
236
+ project.spec.default_function_node_selector[key] = val
237
+
231
238
  if parameters:
232
239
  # Enable setting project parameters at load time, can be used to customize the project_setup
233
240
  for key, val in parameters.items():
@@ -2086,7 +2093,7 @@ class MlrunProject(ModelObj):
2086
2093
  self,
2087
2094
  func: typing.Union[str, mlrun.runtimes.BaseRuntime] = None,
2088
2095
  name: str = "",
2089
- kind: str = "",
2096
+ kind: str = "job",
2090
2097
  image: str = None,
2091
2098
  handler: str = None,
2092
2099
  with_repo: bool = None,
@@ -2173,16 +2180,13 @@ class MlrunProject(ModelObj):
2173
2180
  if func is None and not _has_module(handler, kind):
2174
2181
  # if function path is not provided and it is not a module (no ".")
2175
2182
  # use the current notebook as default
2176
- if not is_ipython:
2177
- raise ValueError(
2178
- "Function path or module must be specified (when not running inside a Notebook)"
2179
- )
2180
- from IPython import get_ipython
2183
+ if is_ipython:
2184
+ from IPython import get_ipython
2181
2185
 
2182
- kernel = get_ipython()
2183
- func = nuclio.utils.notebook_file_name(kernel)
2184
- if func.startswith(path.abspath(self.spec.context)):
2185
- func = path.relpath(func, self.spec.context)
2186
+ kernel = get_ipython()
2187
+ func = nuclio.utils.notebook_file_name(kernel)
2188
+ if func.startswith(path.abspath(self.spec.context)):
2189
+ func = path.relpath(func, self.spec.context)
2186
2190
 
2187
2191
  func = func or ""
2188
2192
 
@@ -3340,7 +3344,7 @@ class MlrunProject(ModelObj):
3340
3344
  logger.warning(
3341
3345
  f"Image was successfully built, but failed to delete temporary function {function.metadata.name}."
3342
3346
  " To remove the function, attempt to manually delete it.",
3343
- exc=repr(exc),
3347
+ exc=mlrun.errors.err_to_str(exc),
3344
3348
  )
3345
3349
 
3346
3350
  return result
@@ -3688,7 +3692,10 @@ class MlrunProject(ModelObj):
3688
3692
  self.spec.remove_custom_packager(packager=packager)
3689
3693
 
3690
3694
  def store_api_gateway(
3691
- self, api_gateway: mlrun.runtimes.nuclio.api_gateway.APIGateway
3695
+ self,
3696
+ api_gateway: mlrun.runtimes.nuclio.api_gateway.APIGateway,
3697
+ wait_for_readiness=True,
3698
+ max_wait_time=90,
3692
3699
  ) -> mlrun.runtimes.nuclio.api_gateway.APIGateway:
3693
3700
  """
3694
3701
  Creates or updates a Nuclio API Gateway using the provided APIGateway object.
@@ -3699,7 +3706,11 @@ class MlrunProject(ModelObj):
3699
3706
  Nuclio docs here: https://docs.nuclio.io/en/latest/reference/api-gateway/http.html
3700
3707
 
3701
3708
  :param api_gateway: An instance of :py:class:`~mlrun.runtimes.nuclio.APIGateway` representing the configuration
3702
- of the API Gateway to be created
3709
+ of the API Gateway to be created or updated.
3710
+ :param wait_for_readiness: (Optional) A boolean indicating whether to wait for the API Gateway to become ready
3711
+ after creation or update (default is True)
3712
+ :param max_wait_time: (Optional) Maximum time to wait for API Gateway readiness in seconds (default is 90s)
3713
+
3703
3714
 
3704
3715
  @return: An instance of :py:class:`~mlrun.runtimes.nuclio.APIGateway` with all fields populated based on the
3705
3716
  information retrieved from the Nuclio API
@@ -3715,6 +3726,9 @@ class MlrunProject(ModelObj):
3715
3726
  api_gateway = mlrun.runtimes.nuclio.api_gateway.APIGateway.from_scheme(
3716
3727
  api_gateway_json
3717
3728
  )
3729
+ if wait_for_readiness:
3730
+ api_gateway.wait_for_readiness(max_wait_time=max_wait_time)
3731
+
3718
3732
  return api_gateway
3719
3733
 
3720
3734
  def list_api_gateways(self) -> list[mlrun.runtimes.nuclio.api_gateway.APIGateway]:
@@ -3743,7 +3757,8 @@ class MlrunProject(ModelObj):
3743
3757
  mlrun.runtimes.nuclio.APIGateway: An instance of APIGateway.
3744
3758
  """
3745
3759
 
3746
- return mlrun.db.get_run_db().get_api_gateway(name=name, project=self.name)
3760
+ gateway = mlrun.db.get_run_db().get_api_gateway(name=name, project=self.name)
3761
+ return mlrun.runtimes.nuclio.api_gateway.APIGateway.from_scheme(gateway)
3747
3762
 
3748
3763
  def delete_api_gateway(
3749
3764
  self,
@@ -3933,10 +3948,6 @@ def _init_function_from_dict(
3933
3948
  tag = f.get("tag", None)
3934
3949
 
3935
3950
  has_module = _has_module(handler, kind)
3936
- if not url and "spec" not in f and not has_module:
3937
- # function must point to a file or a module or have a spec
3938
- raise ValueError("Function missing a url or a spec or a module")
3939
-
3940
3951
  relative_url = url
3941
3952
  url, in_context = project.get_item_absolute_path(url)
3942
3953
 
@@ -3996,7 +4007,7 @@ def _init_function_from_dict(
3996
4007
  tag=tag,
3997
4008
  )
3998
4009
 
3999
- elif image and kind in mlrun.runtimes.RuntimeKinds.nuclio_runtimes():
4010
+ elif kind in mlrun.runtimes.RuntimeKinds.nuclio_runtimes():
4000
4011
  func = new_function(
4001
4012
  name,
4002
4013
  command=relative_url,
@@ -4005,7 +4016,7 @@ def _init_function_from_dict(
4005
4016
  handler=handler,
4006
4017
  tag=tag,
4007
4018
  )
4008
- if kind != mlrun.runtimes.RuntimeKinds.application:
4019
+ if image and kind != mlrun.runtimes.RuntimeKinds.application:
4009
4020
  logger.info("Function code not specified, setting entry point to image")
4010
4021
  func.from_image(image)
4011
4022
  else:
mlrun/run.py CHANGED
@@ -389,6 +389,8 @@ def import_function_to_dict(url, secrets=None):
389
389
  code = get_in(runtime, "spec.build.functionSourceCode")
390
390
  update_in(runtime, "metadata.build.code_origin", url)
391
391
  cmd = code_file = get_in(runtime, "spec.command", "")
392
+ # use kind = "job" by default if not specified
393
+ runtime.setdefault("kind", "job")
392
394
  if " " in cmd:
393
395
  code_file = cmd[: cmd.find(" ")]
394
396
  if runtime["kind"] in ["", "local"]:
@@ -535,7 +537,7 @@ def new_function(
535
537
  if source:
536
538
  runner.spec.build.source = source
537
539
  if handler:
538
- if kind in [RuntimeKinds.serving, RuntimeKinds.application]:
540
+ if kind in RuntimeKinds.handlerless_runtimes():
539
541
  raise MLRunInvalidArgumentError(
540
542
  f"Handler is not supported for {kind} runtime"
541
543
  )
@@ -628,6 +630,8 @@ def code_to_function(
628
630
  - mpijob: run distributed Horovod jobs over the MPI job operator
629
631
  - spark: run distributed Spark job using Spark Kubernetes Operator
630
632
  - remote-spark: run distributed Spark job on remote Spark service
633
+ - databricks: run code on Databricks cluster (python scripts, Spark etc.)
634
+ - application: run a long living application (e.g. a web server, UI, etc.)
631
635
 
632
636
  Learn more about [Kinds of function (runtimes)](../concepts/functions-overview.html).
633
637
 
@@ -154,6 +154,22 @@ class RuntimeKinds:
154
154
  RuntimeKinds.application,
155
155
  ]
156
156
 
157
+ @staticmethod
158
+ def pure_nuclio_deployed_runtimes():
159
+ return [
160
+ RuntimeKinds.remote,
161
+ RuntimeKinds.nuclio,
162
+ RuntimeKinds.serving,
163
+ ]
164
+
165
+ @staticmethod
166
+ def handlerless_runtimes():
167
+ return [
168
+ RuntimeKinds.serving,
169
+ # Application runtime handler is internal reverse proxy
170
+ RuntimeKinds.application,
171
+ ]
172
+
157
173
  @staticmethod
158
174
  def local_runtimes():
159
175
  return [
mlrun/runtimes/base.py CHANGED
@@ -23,6 +23,7 @@ from typing import Callable, Optional, Union
23
23
  import requests.exceptions
24
24
  from nuclio.build import mlrun_footer
25
25
 
26
+ import mlrun.common.constants
26
27
  import mlrun.common.schemas
27
28
  import mlrun.common.schemas.model_monitoring.constants as mm_constants
28
29
  import mlrun.db
@@ -634,7 +635,9 @@ class BaseRuntime(ModelObj):
634
635
  image = image or self.spec.image or ""
635
636
 
636
637
  image = enrich_image_url(image, client_version, client_python_version)
637
- if not image.startswith("."):
638
+ if not image.startswith(
639
+ mlrun.common.constants.IMAGE_NAME_ENRICH_REGISTRY_PREFIX
640
+ ):
638
641
  return image
639
642
  registry, repository = get_parsed_docker_registry()
640
643
  if registry:
mlrun/runtimes/kubejob.py CHANGED
@@ -12,7 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import time
16
15
  import warnings
17
16
 
18
17
  import mlrun.common.schemas
@@ -21,7 +20,6 @@ import mlrun.errors
21
20
 
22
21
  from ..kfpops import build_op
23
22
  from ..model import RunObject
24
- from ..utils import get_in, logger
25
23
  from .pod import KubeResource
26
24
 
27
25
 
@@ -65,29 +63,13 @@ class KubejobRuntime(KubeResource):
65
63
  :param pull_at_runtime: load the archive into the container at job runtime vs on build/deploy
66
64
  :param target_dir: target dir on runtime pod or repo clone / archive extraction
67
65
  """
68
- mlrun.utils.helpers.validate_builder_source(source, pull_at_runtime, workdir)
69
-
70
- self.spec.build.source = source
71
- if handler:
72
- self.spec.default_handler = handler
73
- if workdir:
74
- self.spec.workdir = workdir
75
- if target_dir:
76
- self.spec.build.source_code_target_dir = target_dir
77
-
78
- self.spec.build.load_source_on_run = pull_at_runtime
79
- if (
80
- self.spec.build.base_image
81
- and not self.spec.build.commands
82
- and pull_at_runtime
83
- and not self.spec.image
84
- ):
85
- # if we load source from repo and don't need a full build use the base_image as the image
86
- self.spec.image = self.spec.build.base_image
87
- elif not pull_at_runtime:
88
- # clear the image so build will not be skipped
89
- self.spec.build.base_image = self.spec.build.base_image or self.spec.image
90
- self.spec.image = ""
66
+ self._configure_mlrun_build_with_source(
67
+ source=source,
68
+ workdir=workdir,
69
+ handler=handler,
70
+ pull_at_runtime=pull_at_runtime,
71
+ target_dir=target_dir,
72
+ )
91
73
 
92
74
  def build_config(
93
75
  self,
@@ -169,116 +151,39 @@ class KubejobRuntime(KubeResource):
169
151
  show_on_failure: bool = False,
170
152
  force_build: bool = False,
171
153
  ) -> bool:
172
- """deploy function, build container with dependencies
154
+ """Deploy function, build container with dependencies
173
155
 
174
- :param watch: wait for the deploy to complete (and print build logs)
175
- :param with_mlrun: add the current mlrun package to the container build
176
- :param skip_deployed: skip the build if we already have an image for the function
177
- :param is_kfp: deploy as part of a kfp pipeline
178
- :param mlrun_version_specifier: which mlrun package version to include (if not current)
156
+ :param watch: Wait for the deploy to complete (and print build logs)
157
+ :param with_mlrun: Add the current mlrun package to the container build
158
+ :param skip_deployed: Skip the build if we already have an image for the function
159
+ :param is_kfp: Deploy as part of a kfp pipeline
160
+ :param mlrun_version_specifier: Which mlrun package version to include (if not current)
179
161
  :param builder_env: Kaniko builder pod env vars dict (for config/credentials)
180
162
  e.g. builder_env={"GIT_TOKEN": token}
181
- :param show_on_failure: show logs only in case of build failure
182
- :param force_build: set True for force building the image, even when no changes were made
163
+ :param show_on_failure: Show logs only in case of build failure
164
+ :param force_build: Set True for force building the image, even when no changes were made
183
165
 
184
166
  :return: True if the function is ready (deployed)
185
167
  """
186
168
 
187
169
  build = self.spec.build
170
+ with_mlrun = self._resolve_build_with_mlrun(with_mlrun)
188
171
 
189
- if with_mlrun is None:
190
- if build.with_mlrun is not None:
191
- with_mlrun = build.with_mlrun
192
- else:
193
- with_mlrun = build.base_image and not (
194
- build.base_image.startswith("mlrun/")
195
- or "/mlrun/" in build.base_image
196
- )
197
-
198
- if (
199
- not build.source
200
- and not build.commands
201
- and not build.requirements
202
- and not build.extra
203
- and with_mlrun
204
- ):
205
- logger.info(
206
- "Running build to add mlrun package, set "
207
- "with_mlrun=False to skip if its already in the image"
208
- )
209
172
  self.status.state = ""
210
173
  if build.base_image:
211
174
  # clear the image so build will not be skipped
212
175
  self.spec.image = ""
213
176
 
214
- # When we're in pipelines context we must watch otherwise the pipelines pod will exit before the operation
215
- # is actually done. (when a pipelines pod exits, the pipeline step marked as done)
216
- if is_kfp:
217
- watch = True
218
-
219
- ready = False
220
- if self._is_remote_api():
221
- db = self._get_db()
222
- data = db.remote_builder(
223
- self,
224
- with_mlrun,
225
- mlrun_version_specifier,
226
- skip_deployed,
227
- builder_env=builder_env,
228
- force_build=force_build,
229
- )
230
- self.status = data["data"].get("status", None)
231
- self.spec.image = get_in(data, "data.spec.image")
232
- self.spec.build.base_image = self.spec.build.base_image or get_in(
233
- data, "data.spec.build.base_image"
234
- )
235
- # Get the source target dir in case it was enriched due to loading source
236
- self.spec.build.source_code_target_dir = get_in(
237
- data, "data.spec.build.source_code_target_dir"
238
- ) or get_in(data, "data.spec.clone_target_dir")
239
- ready = data.get("ready", False)
240
- if not ready:
241
- logger.info(
242
- f"Started building image: {data.get('data', {}).get('spec', {}).get('build', {}).get('image')}"
243
- )
244
- if watch and not ready:
245
- state = self._build_watch(watch, show_on_failure=show_on_failure)
246
- ready = state == "ready"
247
- self.status.state = state
248
-
249
- if watch and not ready:
250
- raise mlrun.errors.MLRunRuntimeError("Deploy failed")
251
- return ready
252
-
253
- def _build_watch(self, watch=True, logs=True, show_on_failure=False):
254
- db = self._get_db()
255
- offset = 0
256
- try:
257
- text, _ = db.get_builder_status(self, 0, logs=logs)
258
- except mlrun.db.RunDBError:
259
- raise ValueError("function or build process not found")
260
-
261
- def print_log(text):
262
- if text and (not show_on_failure or self.status.state == "error"):
263
- print(text, end="")
264
-
265
- print_log(text)
266
- offset += len(text)
267
- if watch:
268
- while self.status.state in ["pending", "running"]:
269
- time.sleep(2)
270
- if show_on_failure:
271
- text = ""
272
- db.get_builder_status(self, 0, logs=False)
273
- if self.status.state == "error":
274
- # re-read the full log on failure
275
- text, _ = db.get_builder_status(self, offset, logs=logs)
276
- else:
277
- text, _ = db.get_builder_status(self, offset, logs=logs)
278
- print_log(text)
279
- offset += len(text)
280
-
281
- return self.status.state
177
+ return self._build_image(
178
+ builder_env=builder_env,
179
+ force_build=force_build,
180
+ mlrun_version_specifier=mlrun_version_specifier,
181
+ show_on_failure=show_on_failure,
182
+ skip_deployed=skip_deployed,
183
+ watch=watch,
184
+ is_kfp=is_kfp,
185
+ with_mlrun=with_mlrun,
186
+ )
282
187
 
283
188
  def deploy_step(
284
189
  self,
@@ -22,7 +22,8 @@ from requests.auth import HTTPBasicAuth
22
22
  import mlrun
23
23
  import mlrun.common.schemas
24
24
 
25
- from .function import RemoteRuntime, get_fullname
25
+ from ..utils import logger
26
+ from .function import RemoteRuntime, get_fullname, min_nuclio_versions
26
27
  from .serving import ServingRuntime
27
28
 
28
29
  NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH = "basicAuth"
@@ -85,13 +86,14 @@ class BasicAuth(APIGatewayAuthenticator):
85
86
  self,
86
87
  ) -> Optional[dict[str, Optional[mlrun.common.schemas.APIGatewayBasicAuth]]]:
87
88
  return {
88
- "authentication": mlrun.common.schemas.APIGatewayBasicAuth(
89
+ "basicAuth": mlrun.common.schemas.APIGatewayBasicAuth(
89
90
  username=self._username, password=self._password
90
91
  )
91
92
  }
92
93
 
93
94
 
94
95
  class APIGateway:
96
+ @min_nuclio_versions("1.13.1")
95
97
  def __init__(
96
98
  self,
97
99
  project,
@@ -147,6 +149,7 @@ class APIGateway:
147
149
  self.description = description
148
150
  self.canary = canary
149
151
  self.authentication = authentication
152
+ self.state = ""
150
153
 
151
154
  def invoke(
152
155
  self,
@@ -172,6 +175,11 @@ class APIGateway:
172
175
  raise mlrun.errors.MLRunInvalidArgumentError(
173
176
  "Invocation url is not set. Set up gateway's `invoke_url` attribute."
174
177
  )
178
+ if not self.is_ready():
179
+ raise mlrun.errors.MLRunPreconditionFailedError(
180
+ f"API gateway is not ready. " f"Current state: {self.state}"
181
+ )
182
+
175
183
  if (
176
184
  self.authentication.authentication_mode
177
185
  == NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH
@@ -188,6 +196,33 @@ class APIGateway:
188
196
  auth=HTTPBasicAuth(*auth) if auth else None,
189
197
  )
190
198
 
199
+ def wait_for_readiness(self, max_wait_time=90):
200
+ """
201
+ Wait for the API gateway to become ready within the maximum wait time.
202
+
203
+ Parameters:
204
+ max_wait_time: int - Maximum time to wait in seconds (default is 90 seconds).
205
+
206
+ Returns:
207
+ bool: True if the entity becomes ready within the maximum wait time, False otherwise
208
+ """
209
+
210
+ def _ensure_ready():
211
+ if not self.is_ready():
212
+ raise AssertionError(
213
+ f"Waiting for gateway readiness is taking more than {max_wait_time} seconds"
214
+ )
215
+
216
+ return mlrun.utils.helpers.retry_until_successful(
217
+ 3, max_wait_time, logger, False, _ensure_ready
218
+ )
219
+
220
+ def is_ready(self):
221
+ if self.state is not mlrun.common.schemas.api_gateway.APIGatewayState.ready:
222
+ # try to sync the state
223
+ self.sync()
224
+ return self.state == mlrun.common.schemas.api_gateway.APIGatewayState.ready
225
+
191
226
  def sync(self):
192
227
  """
193
228
  Synchronize the API gateway from the server.
@@ -201,6 +236,7 @@ class APIGateway:
201
236
  self.functions = synced_gateway.functions
202
237
  self.canary = synced_gateway.canary
203
238
  self.description = synced_gateway.description
239
+ self.state = synced_gateway.state
204
240
 
205
241
  def with_basic_auth(self, username: str, password: str):
206
242
  """
@@ -247,7 +283,12 @@ class APIGateway:
247
283
  def from_scheme(cls, api_gateway: mlrun.common.schemas.APIGateway):
248
284
  project = api_gateway.metadata.labels.get(PROJECT_NAME_LABEL)
249
285
  functions, canary = cls._resolve_canary(api_gateway.spec.upstreams)
250
- return cls(
286
+ state = (
287
+ api_gateway.status.state
288
+ if api_gateway.status
289
+ else mlrun.common.schemas.APIGatewayState.none
290
+ )
291
+ api_gateway = cls(
251
292
  project=project,
252
293
  description=api_gateway.spec.description,
253
294
  name=api_gateway.spec.name,
@@ -257,15 +298,21 @@ class APIGateway:
257
298
  functions=functions,
258
299
  canary=canary,
259
300
  )
301
+ api_gateway.state = state
302
+ return api_gateway
260
303
 
261
304
  def to_scheme(self) -> mlrun.common.schemas.APIGateway:
262
305
  upstreams = (
263
306
  [
264
307
  mlrun.common.schemas.APIGatewayUpstream(
265
- nucliofunction={"name": function_name},
266
- percentage=percentage,
267
- )
268
- for function_name, percentage in zip(self.functions, self.canary)
308
+ nucliofunction={"name": self.functions[0]},
309
+ percentage=self.canary[0],
310
+ ),
311
+ mlrun.common.schemas.APIGatewayUpstream(
312
+ # do not set percent for the second function,
313
+ # so we can define which function to display as a primary one in UI
314
+ nucliofunction={"name": self.functions[1]},
315
+ ),
269
316
  ]
270
317
  if self.canary
271
318
  else [
@@ -300,7 +347,10 @@ class APIGateway:
300
347
 
301
348
  :return: (str) The invoke URL.
302
349
  """
303
- return urljoin(self.host, self.path)
350
+ host = self.host
351
+ if not self.host.startswith("http"):
352
+ host = f"https://{self.host}"
353
+ return urljoin(host, self.path)
304
354
 
305
355
  def _validate(
306
356
  self,
@@ -223,7 +223,42 @@ class ApplicationRuntime(RemoteRuntime):
223
223
  auth_info: AuthInfo = None,
224
224
  builder_env: dict = None,
225
225
  force_build: bool = False,
226
+ with_mlrun=None,
227
+ skip_deployed=False,
228
+ is_kfp=False,
229
+ mlrun_version_specifier=None,
230
+ show_on_failure: bool = False,
226
231
  ):
232
+ """
233
+ Deploy function, builds the application image if required (self.requires_build()) or force_build is True,
234
+ Once the image is built, the function is deployed.
235
+ :param project: Project name
236
+ :param tag: Function tag
237
+ :param verbose: Set True for verbose logging
238
+ :param auth_info: Service AuthInfo (deprecated and ignored)
239
+ :param builder_env: Env vars dict for source archive config/credentials
240
+ e.g. builder_env={"GIT_TOKEN": token}
241
+ :param force_build: Set True for force building the application image
242
+ :param with_mlrun: Add the current mlrun package to the container build
243
+ :param skip_deployed: Skip the build if we already have an image for the function
244
+ :param is_kfp: Deploy as part of a kfp pipeline
245
+ :param mlrun_version_specifier: Which mlrun package version to include (if not current)
246
+ :param show_on_failure: Show logs only in case of build failure
247
+ :return: True if the function is ready (deployed)
248
+ """
249
+ if self.requires_build() or force_build:
250
+ self._fill_credentials()
251
+ self._build_application_image(
252
+ builder_env=builder_env,
253
+ force_build=force_build,
254
+ watch=True,
255
+ with_mlrun=with_mlrun,
256
+ skip_deployed=skip_deployed,
257
+ is_kfp=is_kfp,
258
+ mlrun_version_specifier=mlrun_version_specifier,
259
+ show_on_failure=show_on_failure,
260
+ )
261
+
227
262
  self._ensure_reverse_proxy_configurations()
228
263
  self._configure_application_sidecar()
229
264
  super().deploy(
@@ -232,7 +267,50 @@ class ApplicationRuntime(RemoteRuntime):
232
267
  verbose,
233
268
  auth_info,
234
269
  builder_env,
235
- force_build,
270
+ )
271
+
272
+ def with_source_archive(
273
+ self, source, workdir=None, pull_at_runtime=True, target_dir=None
274
+ ):
275
+ """load the code from git/tar/zip archive at runtime or build
276
+
277
+ :param source: valid absolute path or URL to git, zip, or tar file, e.g.
278
+ git://github.com/mlrun/something.git
279
+ http://some/url/file.zip
280
+ note path source must exist on the image or exist locally when run is local
281
+ (it is recommended to use 'workdir' when source is a filepath instead)
282
+ :param workdir: working dir relative to the archive root (e.g. './subdir') or absolute to the image root
283
+ :param pull_at_runtime: load the archive into the container at job runtime vs on build/deploy
284
+ :param target_dir: target dir on runtime pod or repo clone / archive extraction
285
+ """
286
+ self._configure_mlrun_build_with_source(
287
+ source=source,
288
+ workdir=workdir,
289
+ pull_at_runtime=pull_at_runtime,
290
+ target_dir=target_dir,
291
+ )
292
+
293
+ def _build_application_image(
294
+ self,
295
+ builder_env: dict = None,
296
+ force_build: bool = False,
297
+ watch=True,
298
+ with_mlrun=None,
299
+ skip_deployed=False,
300
+ is_kfp=False,
301
+ mlrun_version_specifier=None,
302
+ show_on_failure: bool = False,
303
+ ):
304
+ with_mlrun = self._resolve_build_with_mlrun(with_mlrun)
305
+ return self._build_image(
306
+ builder_env=builder_env,
307
+ force_build=force_build,
308
+ mlrun_version_specifier=mlrun_version_specifier,
309
+ show_on_failure=show_on_failure,
310
+ skip_deployed=skip_deployed,
311
+ watch=watch,
312
+ is_kfp=is_kfp,
313
+ with_mlrun=with_mlrun,
236
314
  )
237
315
 
238
316
  def _ensure_reverse_proxy_configurations(self):
@@ -39,11 +39,19 @@ func Handler(context *nuclio.Context, event nuclio.Event) (interface{}, error) {
39
39
  for k, v := range event.GetHeaders() {
40
40
  httpRequest.Header[k] = []string{v.(string)}
41
41
  }
42
+
43
+ // populate query params
44
+ query := httpRequest.URL.Query()
45
+ for k, v := range event.GetFields() {
46
+ query.Set(k, v.(string))
47
+ }
48
+ httpRequest.URL.RawQuery = query.Encode()
49
+
42
50
  recorder := httptest.NewRecorder()
43
51
  reverseProxy.ServeHTTP(recorder, httpRequest)
44
52
 
45
53
  // send request to sidecar
46
- context.Logger.InfoWith("Forwarding request to sidecar", "sidecarUrl", sidecarUrl)
54
+ context.Logger.DebugWith("Forwarding request to sidecar", "sidecarUrl", sidecarUrl, "query", httpRequest.URL.Query())
47
55
  response := recorder.Result()
48
56
 
49
57
  headers := make(map[string]interface{})