Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Application] Introducing application runtime phase I #5234

Merged
merged 50 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
a837fe3
init
alonmr Jan 24, 2024
0f06bea
init2
alonmr Jan 24, 2024
1d446e6
.
alonmr Jan 24, 2024
3ae076f
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Jan 25, 2024
0f159ce
more small stuff
alonmr Jan 25, 2024
78c362a
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Jan 28, 2024
799c437
test-1
alonmr Jan 28, 2024
a16fd8f
fix
alonmr Jan 28, 2024
8ea7c5a
fix
alonmr Jan 28, 2024
0e0f501
.
alonmr Jan 28, 2024
63741ab
ut
alonmr Jan 28, 2024
7198e2b
fixes
alonmr Jan 28, 2024
b587e59
.
alonmr Jan 28, 2024
39a57b5
.
alonmr Jan 28, 2024
67dbd30
.
alonmr Jan 28, 2024
19caea4
Merge remote-tracking branch 'origin/development' into ML-4601
alonmr Feb 11, 2024
8f33e80
fixes
alonmr Feb 11, 2024
3d6c76e
minor
alonmr Feb 12, 2024
65b1146
.
alonmr Feb 13, 2024
0508459
fix
alonmr Feb 13, 2024
1d57b77
.
alonmr Feb 13, 2024
4ebae85
fix
alonmr Feb 13, 2024
4f10cf7
.
alonmr Feb 13, 2024
35baa3c
test
alonmr Feb 13, 2024
53af10b
fixes
alonmr Feb 19, 2024
ff10bb8
copyrigt
alonmr Mar 3, 2024
1d3b944
minor
alonmr Mar 3, 2024
b1c8280
copyright
alonmr Mar 3, 2024
1c034cc
clear image
alonmr Mar 3, 2024
4558065
address initial cr
alonmr Mar 4, 2024
ce5dad1
whitespaces
alonmr Mar 4, 2024
0967197
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Mar 4, 2024
b13d946
fixes
alonmr Mar 4, 2024
ae799aa
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Mar 6, 2024
9926f61
set function from image and ut fixes
alonmr Mar 6, 2024
813b87c
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Mar 11, 2024
31078ab
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Mar 11, 2024
b5ee5e9
add ut and fix
alonmr Mar 12, 2024
b9e3e59
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Mar 12, 2024
8b9249c
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Mar 13, 2024
ec61cd3
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Mar 17, 2024
d048278
cr
alonmr Mar 17, 2024
05d46bd
partial saar review
alonmr Mar 17, 2024
9b08eac
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Mar 17, 2024
15da1fd
.
alonmr Mar 18, 2024
b72c1e7
pre deploy validation
alonmr Mar 18, 2024
7e3df15
Merge branch 'development' of github.com:mlrun/mlrun into ML-4601
alonmr Mar 18, 2024
80a3665
ensure reverse proxy
alonmr Mar 18, 2024
558db4f
tomer cr
alonmr Mar 19, 2024
94ab40d
liran comments
alonmr Mar 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions mlrun/projects/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -3896,6 +3896,18 @@ def _init_function_from_dict(
tag=tag,
)

elif image and kind in mlrun.runtimes.RuntimeKinds.nuclio_runtimes():
TomerShor marked this conversation as resolved.
Show resolved Hide resolved
func = new_function(
name,
command=relative_url,
image=image,
kind=kind,
handler=handler,
tag=tag,
)
if kind != mlrun.runtimes.RuntimeKinds.application:
logger.info("Function code not specified, setting entry point to image")
func.from_image(image)
else:
raise ValueError(f"Unsupported function url:handler {url}:{handler} or no spec")

Expand Down
142 changes: 69 additions & 73 deletions mlrun/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import mlrun.errors
import mlrun.utils.helpers
from mlrun.kfpops import format_summary_from_kfp_run, show_kfp_run
from mlrun.runtimes.nuclio.serving import serving_subkind

from .common.helpers import parse_versioned_object_uri
from .config import config as mlconf
Expand All @@ -58,6 +57,7 @@
)
from .runtimes.databricks_job.databricks_runtime import DatabricksRuntime
from .runtimes.funcdoc import update_function_entry_points
from .runtimes.nuclio.application import ApplicationRuntime
from .runtimes.utils import add_code_metadata, global_context
from .utils import (
extend_hub_uri_if_needed,
Expand Down Expand Up @@ -425,19 +425,19 @@ def import_function_to_dict(url, secrets=None):


def new_function(
name: str = "",
project: str = "",
tag: str = "",
kind: str = "",
command: str = "",
image: str = "",
args: list = None,
runtime=None,
mode=None,
handler: str = None,
source: str = None,
name: Optional[str] = "",
project: Optional[str] = "",
tag: Optional[str] = "",
kind: Optional[str] = "",
command: Optional[str] = "",
image: Optional[str] = "",
args: Optional[list] = None,
runtime: Optional[Union[mlrun.runtimes.BaseRuntime, dict]] = None,
mode: Optional[str] = None,
handler: Optional[str] = None,
source: Optional[str] = None,
requirements: Union[str, list[str]] = None,
kfp=None,
kfp: Optional[bool] = None,
requirements_file: str = "",
):
"""Create a new ML function from base properties
Expand Down Expand Up @@ -535,9 +535,9 @@ def new_function(
if source:
runner.spec.build.source = source
if handler:
if kind == RuntimeKinds.serving:
if kind in [RuntimeKinds.serving, RuntimeKinds.application]:
raise MLRunInvalidArgumentError(
"cannot set the handler for serving runtime"
f"Handler is not supported for {kind} runtime"
)
elif kind in RuntimeKinds.nuclio_runtimes():
runner.spec.function_handler = handler
Expand Down Expand Up @@ -575,22 +575,22 @@ def _process_runtime(command, runtime, kind):


def code_to_function(
name: str = "",
project: str = "",
tag: str = "",
filename: str = "",
handler: str = "",
kind: str = "",
image: str = None,
code_output: str = "",
name: Optional[str] = "",
project: Optional[str] = "",
tag: Optional[str] = "",
filename: Optional[str] = "",
handler: Optional[str] = "",
kind: Optional[str] = "",
image: Optional[str] = None,
code_output: Optional[str] = "",
embed_code: bool = True,
description: str = "",
requirements: Union[str, list[str]] = None,
categories: list[str] = None,
labels: dict[str, str] = None,
with_doc: bool = True,
ignored_tags=None,
requirements_file: str = "",
description: Optional[str] = "",
requirements: Optional[Union[str, list[str]]] = None,
categories: Optional[list[str]] = None,
labels: Optional[dict[str, str]] = None,
with_doc: Optional[bool] = True,
ignored_tags: Optional[str] = None,
requirements_file: Optional[str] = "",
) -> Union[
MpiRuntimeV1Alpha1,
MpiRuntimeV1,
Expand All @@ -602,6 +602,7 @@ def code_to_function(
Spark3Runtime,
RemoteSparkRuntime,
DatabricksRuntime,
ApplicationRuntime,
]:
"""Convenience function to insert code and configure an mlrun runtime.

Expand Down Expand Up @@ -718,35 +719,34 @@ def update_common(fn, spec):
fn.metadata.categories = categories
fn.metadata.labels = labels or fn.metadata.labels

def resolve_nuclio_subkind(kind):
is_nuclio = kind.startswith("nuclio")
subkind = kind[kind.find(":") + 1 :] if is_nuclio and ":" in kind else None
if kind == RuntimeKinds.serving:
is_nuclio = True
subkind = serving_subkind
return is_nuclio, subkind

if (
not embed_code
and not code_output
and (not filename or filename.endswith(".ipynb"))
):
raise ValueError(
"a valid code file must be specified "
"A valid code file must be specified "
"when not using the embed_code option"
)

if kind == RuntimeKinds.databricks and not embed_code:
raise ValueError("databricks tasks only support embed_code=True")
raise ValueError("Databricks tasks only support embed_code=True")

is_nuclio, subkind = resolve_nuclio_subkind(kind)
if kind == RuntimeKinds.application:
if handler:
raise MLRunInvalidArgumentError(
"Handler is not supported for application runtime"
)
filename, handler = ApplicationRuntime.get_filename_and_handler()

is_nuclio, sub_kind = RuntimeKinds.resolve_nuclio_sub_kind(kind)
code_origin = add_name(add_code_metadata(filename), name)

name, spec, code = nuclio.build_file(
filename,
name=name,
handler=handler or "handler",
kind=subkind,
kind=sub_kind,
ignored_tags=ignored_tags,
)
spec["spec"]["env"].append(
Expand All @@ -759,14 +759,14 @@ def resolve_nuclio_subkind(kind):
if not kind and spec_kind not in ["", "Function"]:
kind = spec_kind.lower()

# if its a nuclio subkind, redo nb parsing
is_nuclio, subkind = resolve_nuclio_subkind(kind)
# if its a nuclio sub kind, redo nb parsing
is_nuclio, sub_kind = RuntimeKinds.resolve_nuclio_sub_kind(kind)
if is_nuclio:
name, spec, code = nuclio.build_file(
filename,
name=name,
handler=handler or "handler",
kind=subkind,
kind=sub_kind,
ignored_tags=ignored_tags,
)

Expand All @@ -780,33 +780,29 @@ def resolve_nuclio_subkind(kind):
raise ValueError("code_output option is only used with notebooks")

if is_nuclio:
if subkind == serving_subkind:
r = ServingRuntime()
else:
r = RemoteRuntime()
r.spec.function_kind = subkind
# default_handler is only used in :mlrun subkind, determine the handler to invoke in function.run()
r.spec.default_handler = handler if subkind == "mlrun" else ""
r.spec.function_handler = (
runtime = RuntimeKinds.resolve_nuclio_runtime(kind, sub_kind)
# default_handler is only used in :mlrun sub kind, determine the handler to invoke in function.run()
runtime.spec.default_handler = handler if sub_kind == "mlrun" else ""
runtime.spec.function_handler = (
handler if handler and ":" in handler else get_in(spec, "spec.handler")
)
if not embed_code:
r.spec.source = filename
runtime.spec.source = filename
nuclio_runtime = get_in(spec, "spec.runtime")
if nuclio_runtime and not nuclio_runtime.startswith("py"):
r.spec.nuclio_runtime = nuclio_runtime
runtime.spec.nuclio_runtime = nuclio_runtime
if not name:
raise ValueError("name must be specified")
r.metadata.name = name
r.spec.build.code_origin = code_origin
r.spec.build.origin_filename = filename or (name + ".ipynb")
update_common(r, spec)
return r
raise ValueError("Missing required parameter: name")
runtime.metadata.name = name
runtime.spec.build.code_origin = code_origin
runtime.spec.build.origin_filename = filename or (name + ".ipynb")
update_common(runtime, spec)
return runtime

if kind is None or kind in ["", "Function"]:
raise ValueError("please specify the function kind")
elif kind in RuntimeKinds.all():
r = get_runtime_class(kind)()
runtime = get_runtime_class(kind)()
else:
raise ValueError(f"unsupported runtime ({kind})")

Expand All @@ -815,29 +811,29 @@ def resolve_nuclio_subkind(kind):
if not name:
raise ValueError("name must be specified")
h = get_in(spec, "spec.handler", "").split(":")
r.handler = h[0] if len(h) <= 1 else h[1]
r.metadata = get_in(spec, "spec.metadata")
r.metadata.name = name
build = r.spec.build
runtime.handler = h[0] if len(h) <= 1 else h[1]
runtime.metadata = get_in(spec, "spec.metadata")
runtime.metadata.name = name
build = runtime.spec.build
build.code_origin = code_origin
build.origin_filename = filename or (name + ".ipynb")
build.extra = get_in(spec, "spec.build.extra")
build.extra_args = get_in(spec, "spec.build.extra_args")
build.builder_env = get_in(spec, "spec.build.builder_env")
if not embed_code:
if code_output:
r.spec.command = code_output
runtime.spec.command = code_output
else:
r.spec.command = filename
runtime.spec.command = filename

build.image = get_in(spec, "spec.build.image")
update_common(r, spec)
r.prepare_image_for_deploy()
update_common(runtime, spec)
runtime.prepare_image_for_deploy()

if with_doc:
update_function_entry_points(r, code)
r.spec.default_handler = handler
return r
update_function_entry_points(runtime, code)
runtime.spec.default_handler = handler
return runtime


def _run_pipeline(
Expand Down
35 changes: 35 additions & 0 deletions mlrun/runtimes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
new_v2_model_server,
nuclio_init_hook,
)
from .nuclio.application import ApplicationRuntime
from .nuclio.serving import serving_subkind
from .remotesparkjob import RemoteSparkRuntime
from .sparkjob import Spark3Runtime

Expand Down Expand Up @@ -101,6 +103,7 @@ class RuntimeKinds:
local = "local"
handler = "handler"
databricks = "databricks"
application = "application"

@staticmethod
def all():
Expand All @@ -115,6 +118,7 @@ def all():
RuntimeKinds.mpijob,
RuntimeKinds.local,
RuntimeKinds.databricks,
RuntimeKinds.application,
]

@staticmethod
Expand Down Expand Up @@ -147,6 +151,7 @@ def nuclio_runtimes():
RuntimeKinds.remote,
RuntimeKinds.nuclio,
RuntimeKinds.serving,
RuntimeKinds.application,
]

@staticmethod
Expand Down Expand Up @@ -211,6 +216,35 @@ def requires_image_name_for_execution(kind):
# both spark and remote spark uses different mechanism for assigning images
return kind not in [RuntimeKinds.spark, RuntimeKinds.remotespark]

@staticmethod
def resolve_nuclio_runtime(kind: str, sub_kind: str):
theSaarco marked this conversation as resolved.
Show resolved Hide resolved
kind = kind.split(":")[0]
if kind not in RuntimeKinds.nuclio_runtimes():
raise ValueError(
f"Kind {kind} is not a nuclio runtime, available runtimes are {RuntimeKinds.nuclio_runtimes()}"
)

if sub_kind == serving_subkind:
return ServingRuntime()

if kind == RuntimeKinds.application:
return ApplicationRuntime()

runtime = RemoteRuntime()
runtime.spec.function_kind = sub_kind
return runtime

@staticmethod
def resolve_nuclio_sub_kind(kind):
is_nuclio = kind.startswith("nuclio")
sub_kind = kind[kind.find(":") + 1 :] if is_nuclio and ":" in kind else None
if kind == RuntimeKinds.serving:
is_nuclio = True
sub_kind = serving_subkind
elif kind == RuntimeKinds.application:
is_nuclio = True
return is_nuclio, sub_kind


def get_runtime_class(kind: str):
if kind == RuntimeKinds.mpijob:
Expand All @@ -228,6 +262,7 @@ def get_runtime_class(kind: str):
RuntimeKinds.local: LocalRuntime,
RuntimeKinds.remotespark: RemoteSparkRuntime,
RuntimeKinds.databricks: DatabricksRuntime,
RuntimeKinds.application: ApplicationRuntime,
}

return kind_runtime_map[kind]
2 changes: 1 addition & 1 deletion mlrun/runtimes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ def with_requirements(
requirements: Optional[list[str]] = None,
overwrite: bool = False,
prepare_image_for_deploy: bool = True,
requirements_file: str = "",
requirements_file: Optional[str] = "",
):
"""add package requirements from file or list to build spec.

Expand Down
15 changes: 15 additions & 0 deletions mlrun/runtimes/nuclio/application/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2024 Iguazio
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .application import ApplicationRuntime