mlrun 1.7.0rc15__py3-none-any.whl → 1.7.0rc17__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.
- mlrun/__init__.py +10 -1
- mlrun/__main__.py +18 -4
- mlrun/alerts/__init__.py +15 -0
- mlrun/alerts/alert.py +144 -0
- mlrun/artifacts/__init__.py +7 -1
- mlrun/artifacts/base.py +28 -3
- mlrun/artifacts/dataset.py +8 -0
- mlrun/artifacts/manager.py +18 -0
- mlrun/artifacts/model.py +8 -1
- mlrun/artifacts/plots.py +13 -0
- mlrun/common/schemas/__init__.py +10 -2
- mlrun/common/schemas/alert.py +64 -5
- mlrun/common/schemas/api_gateway.py +4 -0
- mlrun/common/schemas/artifact.py +15 -0
- mlrun/common/schemas/auth.py +2 -0
- mlrun/common/schemas/model_monitoring/__init__.py +4 -1
- mlrun/common/schemas/model_monitoring/constants.py +17 -1
- mlrun/common/schemas/model_monitoring/model_endpoints.py +60 -1
- mlrun/common/schemas/project.py +5 -1
- mlrun/config.py +11 -4
- mlrun/datastore/datastore_profile.py +10 -7
- mlrun/db/base.py +24 -4
- mlrun/db/httpdb.py +97 -43
- mlrun/db/nopdb.py +25 -4
- mlrun/errors.py +5 -0
- mlrun/launcher/base.py +3 -2
- mlrun/lists.py +4 -0
- mlrun/model.py +15 -8
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/applications/_application_steps.py +1 -2
- mlrun/model_monitoring/applications/context.py +1 -1
- mlrun/model_monitoring/applications/histogram_data_drift.py +64 -38
- mlrun/model_monitoring/db/__init__.py +2 -0
- mlrun/model_monitoring/db/stores/base/store.py +9 -36
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +63 -110
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +56 -202
- mlrun/model_monitoring/db/tsdb/__init__.py +71 -0
- mlrun/model_monitoring/db/tsdb/base.py +135 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +442 -0
- mlrun/model_monitoring/db/v3io_tsdb_reader.py +134 -0
- mlrun/model_monitoring/stream_processing.py +46 -210
- mlrun/model_monitoring/writer.py +50 -100
- mlrun/platforms/__init__.py +10 -9
- mlrun/platforms/iguazio.py +19 -200
- mlrun/projects/operations.py +11 -7
- mlrun/projects/pipelines.py +13 -76
- mlrun/projects/project.py +62 -17
- mlrun/render.py +9 -3
- mlrun/run.py +5 -38
- mlrun/runtimes/__init__.py +1 -0
- mlrun/runtimes/base.py +3 -3
- mlrun/runtimes/kubejob.py +2 -1
- mlrun/runtimes/nuclio/api_gateway.py +163 -77
- mlrun/runtimes/nuclio/application/application.py +160 -7
- mlrun/runtimes/nuclio/function.py +25 -45
- mlrun/runtimes/pod.py +16 -36
- mlrun/runtimes/remotesparkjob.py +1 -1
- mlrun/runtimes/sparkjob/spark3job.py +1 -1
- mlrun/runtimes/utils.py +0 -38
- mlrun/track/tracker.py +2 -1
- mlrun/utils/helpers.py +51 -31
- mlrun/utils/logger.py +11 -6
- mlrun/utils/notifications/notification/base.py +1 -1
- mlrun/utils/notifications/notification/slack.py +9 -4
- mlrun/utils/notifications/notification/webhook.py +1 -1
- mlrun/utils/notifications/notification_pusher.py +21 -14
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/METADATA +4 -3
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/RECORD +75 -69
- mlrun/kfpops.py +0 -860
- mlrun/platforms/other.py +0 -305
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/WHEEL +0 -0
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc15.dist-info → mlrun-1.7.0rc17.dist-info}/top_level.txt +0 -0
mlrun/run.py
CHANGED
|
@@ -29,11 +29,13 @@ from typing import Optional, Union
|
|
|
29
29
|
import nuclio
|
|
30
30
|
import yaml
|
|
31
31
|
from kfp import Client
|
|
32
|
+
from mlrun_pipelines.common.models import RunStatuses
|
|
33
|
+
from mlrun_pipelines.common.ops import format_summary_from_kfp_run, show_kfp_run
|
|
34
|
+
from mlrun_pipelines.models import PipelineRun
|
|
32
35
|
|
|
33
36
|
import mlrun.common.schemas
|
|
34
37
|
import mlrun.errors
|
|
35
38
|
import mlrun.utils.helpers
|
|
36
|
-
from mlrun.kfpops import format_summary_from_kfp_run, show_kfp_run
|
|
37
39
|
|
|
38
40
|
from .common.helpers import parse_versioned_object_uri
|
|
39
41
|
from .config import config as mlconf
|
|
@@ -68,41 +70,6 @@ from .utils import (
|
|
|
68
70
|
)
|
|
69
71
|
|
|
70
72
|
|
|
71
|
-
class RunStatuses:
|
|
72
|
-
succeeded = "Succeeded"
|
|
73
|
-
failed = "Failed"
|
|
74
|
-
skipped = "Skipped"
|
|
75
|
-
error = "Error"
|
|
76
|
-
running = "Running"
|
|
77
|
-
|
|
78
|
-
@staticmethod
|
|
79
|
-
def all():
|
|
80
|
-
return [
|
|
81
|
-
RunStatuses.succeeded,
|
|
82
|
-
RunStatuses.failed,
|
|
83
|
-
RunStatuses.skipped,
|
|
84
|
-
RunStatuses.error,
|
|
85
|
-
RunStatuses.running,
|
|
86
|
-
]
|
|
87
|
-
|
|
88
|
-
@staticmethod
|
|
89
|
-
def stable_statuses():
|
|
90
|
-
return [
|
|
91
|
-
RunStatuses.succeeded,
|
|
92
|
-
RunStatuses.failed,
|
|
93
|
-
RunStatuses.skipped,
|
|
94
|
-
RunStatuses.error,
|
|
95
|
-
]
|
|
96
|
-
|
|
97
|
-
@staticmethod
|
|
98
|
-
def transient_statuses():
|
|
99
|
-
return [
|
|
100
|
-
status
|
|
101
|
-
for status in RunStatuses.all()
|
|
102
|
-
if status not in RunStatuses.stable_statuses()
|
|
103
|
-
]
|
|
104
|
-
|
|
105
|
-
|
|
106
73
|
def function_to_module(code="", workdir=None, secrets=None, silent=False):
|
|
107
74
|
"""Load code, notebook or mlrun function as .py module
|
|
108
75
|
this function can import a local/remote py file or notebook
|
|
@@ -1021,7 +988,7 @@ def get_pipeline(
|
|
|
1021
988
|
:param project: the project of the pipeline run
|
|
1022
989
|
:param remote: read kfp data from mlrun service (default=True)
|
|
1023
990
|
|
|
1024
|
-
:return: kfp run
|
|
991
|
+
:return: kfp run
|
|
1025
992
|
"""
|
|
1026
993
|
namespace = namespace or mlconf.namespace
|
|
1027
994
|
if remote:
|
|
@@ -1045,7 +1012,7 @@ def get_pipeline(
|
|
|
1045
1012
|
not format_
|
|
1046
1013
|
or format_ == mlrun.common.schemas.PipelinesFormat.summary.value
|
|
1047
1014
|
):
|
|
1048
|
-
resp = format_summary_from_kfp_run(resp)
|
|
1015
|
+
resp = format_summary_from_kfp_run(PipelineRun(resp))
|
|
1049
1016
|
|
|
1050
1017
|
show_kfp_run(resp)
|
|
1051
1018
|
return resp
|
mlrun/runtimes/__init__.py
CHANGED
|
@@ -43,6 +43,7 @@ from .nuclio import (
|
|
|
43
43
|
new_v2_model_server,
|
|
44
44
|
nuclio_init_hook,
|
|
45
45
|
)
|
|
46
|
+
from .nuclio.api_gateway import APIGateway
|
|
46
47
|
from .nuclio.application import ApplicationRuntime
|
|
47
48
|
from .nuclio.serving import serving_subkind
|
|
48
49
|
from .remotesparkjob import RemoteSparkRuntime
|
mlrun/runtimes/base.py
CHANGED
|
@@ -21,6 +21,7 @@ from os import environ
|
|
|
21
21
|
from typing import Callable, Optional, Union
|
|
22
22
|
|
|
23
23
|
import requests.exceptions
|
|
24
|
+
from mlrun_pipelines.common.ops import mlrun_op
|
|
24
25
|
from nuclio.build import mlrun_footer
|
|
25
26
|
|
|
26
27
|
import mlrun.common.constants
|
|
@@ -37,7 +38,6 @@ from mlrun.utils.helpers import generate_object_uri, verify_field_regex
|
|
|
37
38
|
from ..config import config
|
|
38
39
|
from ..datastore import store_manager
|
|
39
40
|
from ..errors import err_to_str
|
|
40
|
-
from ..kfpops import mlrun_op
|
|
41
41
|
from ..lists import RunList
|
|
42
42
|
from ..model import BaseMetadata, HyperParamOptions, ImageBuilder, ModelObj, RunObject
|
|
43
43
|
from ..utils import (
|
|
@@ -707,11 +707,11 @@ class BaseRuntime(ModelObj):
|
|
|
707
707
|
"key": "the_key".
|
|
708
708
|
:param auto_build: when set to True and the function require build it will be built on the first
|
|
709
709
|
function run, use only if you dont plan on changing the build config between runs
|
|
710
|
-
:return:
|
|
710
|
+
:return: mlrun_pipelines.models.PipelineNodeWrapper
|
|
711
711
|
"""
|
|
712
712
|
|
|
713
713
|
# if the function contain KFP PipelineParams (futures) pass the full spec to the
|
|
714
|
-
#
|
|
714
|
+
# PipelineNodeWrapper this way KFP will substitute the params with previous step outputs
|
|
715
715
|
if use_db and not self._has_pipeline_param():
|
|
716
716
|
# if the same function is built as part of the pipeline we do not use the versioned function
|
|
717
717
|
# rather the latest function w the same tag so we can pick up the updated image/status
|
mlrun/runtimes/kubejob.py
CHANGED
|
@@ -14,11 +14,12 @@
|
|
|
14
14
|
|
|
15
15
|
import warnings
|
|
16
16
|
|
|
17
|
+
from mlrun_pipelines.common.ops import build_op
|
|
18
|
+
|
|
17
19
|
import mlrun.common.schemas
|
|
18
20
|
import mlrun.db
|
|
19
21
|
import mlrun.errors
|
|
20
22
|
|
|
21
|
-
from ..kfpops import build_op
|
|
22
23
|
from ..model import RunObject
|
|
23
24
|
from .pod import KubeResource
|
|
24
25
|
|
|
@@ -17,31 +17,31 @@ from typing import Optional, Union
|
|
|
17
17
|
from urllib.parse import urljoin
|
|
18
18
|
|
|
19
19
|
import requests
|
|
20
|
-
from
|
|
20
|
+
from nuclio.auth import AuthInfo as NuclioAuthInfo
|
|
21
|
+
from nuclio.auth import AuthKinds as NuclioAuthKinds
|
|
21
22
|
|
|
22
23
|
import mlrun
|
|
23
|
-
import mlrun.common.schemas
|
|
24
|
+
import mlrun.common.schemas as schemas
|
|
25
|
+
import mlrun.common.types
|
|
26
|
+
from mlrun.model import ModelObj
|
|
27
|
+
from mlrun.platforms.iguazio import min_iguazio_versions
|
|
28
|
+
from mlrun.utils import logger
|
|
24
29
|
|
|
25
|
-
from
|
|
26
|
-
from ..utils import logger
|
|
27
|
-
from .function import RemoteRuntime, get_fullname, min_nuclio_versions
|
|
28
|
-
from .serving import ServingRuntime
|
|
30
|
+
from .function import get_fullname, min_nuclio_versions
|
|
29
31
|
|
|
30
|
-
NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH = "basicAuth"
|
|
31
|
-
NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_NONE = "none"
|
|
32
32
|
PROJECT_NAME_LABEL = "nuclio.io/project-name"
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
class APIGatewayAuthenticator(typing.Protocol):
|
|
36
36
|
@property
|
|
37
37
|
def authentication_mode(self) -> str:
|
|
38
|
-
return
|
|
38
|
+
return schemas.APIGatewayAuthenticationMode.none.value
|
|
39
39
|
|
|
40
40
|
@classmethod
|
|
41
|
-
def from_scheme(cls, api_gateway_spec:
|
|
41
|
+
def from_scheme(cls, api_gateway_spec: schemas.APIGatewaySpec):
|
|
42
42
|
if (
|
|
43
43
|
api_gateway_spec.authenticationMode
|
|
44
|
-
==
|
|
44
|
+
== schemas.APIGatewayAuthenticationMode.basic.value
|
|
45
45
|
):
|
|
46
46
|
if api_gateway_spec.authentication:
|
|
47
47
|
return BasicAuth(
|
|
@@ -50,12 +50,17 @@ class APIGatewayAuthenticator(typing.Protocol):
|
|
|
50
50
|
)
|
|
51
51
|
else:
|
|
52
52
|
return BasicAuth()
|
|
53
|
+
elif (
|
|
54
|
+
api_gateway_spec.authenticationMode
|
|
55
|
+
== schemas.APIGatewayAuthenticationMode.access_key.value
|
|
56
|
+
):
|
|
57
|
+
return AccessKeyAuth()
|
|
53
58
|
else:
|
|
54
59
|
return NoneAuth()
|
|
55
60
|
|
|
56
61
|
def to_scheme(
|
|
57
62
|
self,
|
|
58
|
-
) -> Optional[dict[str, Optional[
|
|
63
|
+
) -> Optional[dict[str, Optional[schemas.APIGatewayBasicAuth]]]:
|
|
59
64
|
return None
|
|
60
65
|
|
|
61
66
|
|
|
@@ -81,18 +86,28 @@ class BasicAuth(APIGatewayAuthenticator):
|
|
|
81
86
|
|
|
82
87
|
@property
|
|
83
88
|
def authentication_mode(self) -> str:
|
|
84
|
-
return
|
|
89
|
+
return schemas.APIGatewayAuthenticationMode.basic.value
|
|
85
90
|
|
|
86
91
|
def to_scheme(
|
|
87
92
|
self,
|
|
88
|
-
) -> Optional[dict[str, Optional[
|
|
93
|
+
) -> Optional[dict[str, Optional[schemas.APIGatewayBasicAuth]]]:
|
|
89
94
|
return {
|
|
90
|
-
"basicAuth":
|
|
95
|
+
"basicAuth": schemas.APIGatewayBasicAuth(
|
|
91
96
|
username=self._username, password=self._password
|
|
92
97
|
)
|
|
93
98
|
}
|
|
94
99
|
|
|
95
100
|
|
|
101
|
+
class AccessKeyAuth(APIGatewayAuthenticator):
|
|
102
|
+
"""
|
|
103
|
+
An API gateway authenticator with access key authentication.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def authentication_mode(self) -> str:
|
|
108
|
+
return schemas.APIGatewayAuthenticationMode.access_key.value
|
|
109
|
+
|
|
110
|
+
|
|
96
111
|
class APIGatewayMetadata(ModelObj):
|
|
97
112
|
_dict_fields = ["name", "namespace", "labels", "annotations", "creation_timestamp"]
|
|
98
113
|
|
|
@@ -138,17 +153,17 @@ class APIGatewaySpec(ModelObj):
|
|
|
138
153
|
def __init__(
|
|
139
154
|
self,
|
|
140
155
|
functions: Union[
|
|
141
|
-
list[
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
],
|
|
149
|
-
RemoteRuntime,
|
|
150
|
-
ServingRuntime,
|
|
156
|
+
list[
|
|
157
|
+
Union[
|
|
158
|
+
str,
|
|
159
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
160
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
161
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
162
|
+
]
|
|
151
163
|
],
|
|
164
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
165
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
166
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
152
167
|
],
|
|
153
168
|
project: str = None,
|
|
154
169
|
description: str = "",
|
|
@@ -156,20 +171,24 @@ class APIGatewaySpec(ModelObj):
|
|
|
156
171
|
path: str = "/",
|
|
157
172
|
authentication: Optional[APIGatewayAuthenticator] = NoneAuth(),
|
|
158
173
|
canary: Optional[list[int]] = None,
|
|
174
|
+
ports: Optional[list[int]] = None,
|
|
159
175
|
):
|
|
160
176
|
"""
|
|
161
177
|
:param functions: The list of functions associated with the API gateway
|
|
162
178
|
Can be a list of function names (["my-func1", "my-func2"])
|
|
163
179
|
or a list or a single entity of
|
|
164
180
|
:py:class:`~mlrun.runtimes.nuclio.function.RemoteRuntime` OR
|
|
165
|
-
:py:class:`~mlrun.runtimes.nuclio.serving.ServingRuntime`
|
|
181
|
+
:py:class:`~mlrun.runtimes.nuclio.serving.ServingRuntime` OR
|
|
182
|
+
:py:class:`~mlrun.runtimes.nuclio.application.ApplicationRuntime`
|
|
166
183
|
:param project: The project name
|
|
167
184
|
:param description: Optional description of the API gateway
|
|
168
185
|
:param path: Optional path of the API gateway, default value is "/"
|
|
169
186
|
:param authentication: The authentication for the API gateway of type
|
|
170
187
|
:py:class:`~mlrun.runtimes.nuclio.api_gateway.BasicAuth`
|
|
171
188
|
:param host: The host of the API gateway (optional). If not set, it will be automatically generated
|
|
172
|
-
:param canary: The canary percents for the API gateway of type list[int]; for instance: [20,80]
|
|
189
|
+
:param canary: The canary percents for the API gateway of type list[int]; for instance: [20,80] (optional)
|
|
190
|
+
:param ports: The ports of the API gateway, as a list of integers that correspond to the functions in the
|
|
191
|
+
functions list. for instance: [8050] or [8050, 8081] (optional)
|
|
173
192
|
"""
|
|
174
193
|
self.description = description
|
|
175
194
|
self.host = host
|
|
@@ -178,26 +197,28 @@ class APIGatewaySpec(ModelObj):
|
|
|
178
197
|
self.functions = functions
|
|
179
198
|
self.canary = canary
|
|
180
199
|
self.project = project
|
|
200
|
+
self.ports = ports
|
|
181
201
|
|
|
182
|
-
self.validate(project=project, functions=functions, canary=canary)
|
|
202
|
+
self.validate(project=project, functions=functions, canary=canary, ports=ports)
|
|
183
203
|
|
|
184
204
|
def validate(
|
|
185
205
|
self,
|
|
186
206
|
project: str,
|
|
187
207
|
functions: Union[
|
|
188
|
-
list[
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
],
|
|
196
|
-
RemoteRuntime,
|
|
197
|
-
ServingRuntime,
|
|
208
|
+
list[
|
|
209
|
+
Union[
|
|
210
|
+
str,
|
|
211
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
212
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
213
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
214
|
+
]
|
|
198
215
|
],
|
|
216
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
217
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
218
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
199
219
|
],
|
|
200
220
|
canary: Optional[list[int]] = None,
|
|
221
|
+
ports: Optional[list[int]] = None,
|
|
201
222
|
):
|
|
202
223
|
self.functions = self._validate_functions(project=project, functions=functions)
|
|
203
224
|
|
|
@@ -205,6 +226,10 @@ class APIGatewaySpec(ModelObj):
|
|
|
205
226
|
if canary:
|
|
206
227
|
self.canary = self._validate_canary(canary)
|
|
207
228
|
|
|
229
|
+
# validating ports
|
|
230
|
+
if ports:
|
|
231
|
+
self.ports = self._validate_ports(ports)
|
|
232
|
+
|
|
208
233
|
def _validate_canary(self, canary: list[int]):
|
|
209
234
|
if len(self.functions) != len(canary):
|
|
210
235
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
@@ -221,20 +246,29 @@ class APIGatewaySpec(ModelObj):
|
|
|
221
246
|
)
|
|
222
247
|
return canary
|
|
223
248
|
|
|
249
|
+
def _validate_ports(self, ports):
|
|
250
|
+
if len(self.functions) != len(ports):
|
|
251
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
252
|
+
"Function and port lists lengths do not match"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
return ports
|
|
256
|
+
|
|
224
257
|
@staticmethod
|
|
225
258
|
def _validate_functions(
|
|
226
259
|
project: str,
|
|
227
260
|
functions: Union[
|
|
228
|
-
list[
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
],
|
|
236
|
-
Union[RemoteRuntime, ServingRuntime],
|
|
261
|
+
list[
|
|
262
|
+
Union[
|
|
263
|
+
str,
|
|
264
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
265
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
266
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
267
|
+
]
|
|
237
268
|
],
|
|
269
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
270
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
271
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
238
272
|
],
|
|
239
273
|
):
|
|
240
274
|
if not isinstance(functions, list):
|
|
@@ -312,8 +346,9 @@ class APIGateway(ModelObj):
|
|
|
312
346
|
def invoke(
|
|
313
347
|
self,
|
|
314
348
|
method="POST",
|
|
315
|
-
headers: dict =
|
|
316
|
-
|
|
349
|
+
headers: dict = None,
|
|
350
|
+
credentials: Optional[tuple[str, str]] = None,
|
|
351
|
+
path: Optional[str] = None,
|
|
317
352
|
**kwargs,
|
|
318
353
|
):
|
|
319
354
|
"""
|
|
@@ -321,7 +356,9 @@ class APIGateway(ModelObj):
|
|
|
321
356
|
|
|
322
357
|
:param method: (str, optional) The HTTP method for the invocation.
|
|
323
358
|
:param headers: (dict, optional) The HTTP headers for the invocation.
|
|
324
|
-
:param
|
|
359
|
+
:param credentials: (Optional[tuple[str, str]], optional) The (username,password) for the invocation if required
|
|
360
|
+
can also be set by the environment variable (_, V3IO_ACCESS_KEY) for access key authentication.
|
|
361
|
+
:param path: (str, optional) The sub-path for the invocation.
|
|
325
362
|
:param kwargs: (dict) Additional keyword arguments.
|
|
326
363
|
|
|
327
364
|
:return: The response from the API gateway invocation.
|
|
@@ -338,20 +375,44 @@ class APIGateway(ModelObj):
|
|
|
338
375
|
f"API gateway is not ready. " f"Current state: {self.state}"
|
|
339
376
|
)
|
|
340
377
|
|
|
378
|
+
auth = None
|
|
379
|
+
|
|
341
380
|
if (
|
|
342
381
|
self.spec.authentication.authentication_mode
|
|
343
|
-
==
|
|
344
|
-
and not auth
|
|
382
|
+
== schemas.APIGatewayAuthenticationMode.basic.value
|
|
345
383
|
):
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
384
|
+
if not credentials:
|
|
385
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
386
|
+
"API Gateway invocation requires authentication. Please pass credentials"
|
|
387
|
+
)
|
|
388
|
+
auth = NuclioAuthInfo(
|
|
389
|
+
username=credentials[0], password=credentials[1]
|
|
390
|
+
).to_requests_auth()
|
|
391
|
+
|
|
392
|
+
if (
|
|
393
|
+
self.spec.authentication.authentication_mode
|
|
394
|
+
== schemas.APIGatewayAuthenticationMode.access_key.value
|
|
395
|
+
):
|
|
396
|
+
# inject access key from env
|
|
397
|
+
if credentials:
|
|
398
|
+
auth = NuclioAuthInfo(
|
|
399
|
+
username=credentials[0],
|
|
400
|
+
password=credentials[1],
|
|
401
|
+
mode=NuclioAuthKinds.iguazio,
|
|
402
|
+
).to_requests_auth()
|
|
403
|
+
else:
|
|
404
|
+
auth = NuclioAuthInfo().from_envvar().to_requests_auth()
|
|
405
|
+
if not auth:
|
|
406
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
407
|
+
"API Gateway invocation requires authentication. Please set V3IO_ACCESS_KEY env var"
|
|
408
|
+
)
|
|
409
|
+
url = urljoin(self.invoke_url, path or "")
|
|
349
410
|
return requests.request(
|
|
350
411
|
method=method,
|
|
351
|
-
url=
|
|
352
|
-
headers=headers,
|
|
412
|
+
url=url,
|
|
413
|
+
headers=headers or {},
|
|
414
|
+
auth=auth,
|
|
353
415
|
**kwargs,
|
|
354
|
-
auth=HTTPBasicAuth(*auth) if auth else None,
|
|
355
416
|
)
|
|
356
417
|
|
|
357
418
|
def wait_for_readiness(self, max_wait_time=90):
|
|
@@ -376,10 +437,10 @@ class APIGateway(ModelObj):
|
|
|
376
437
|
)
|
|
377
438
|
|
|
378
439
|
def is_ready(self):
|
|
379
|
-
if self.state is not
|
|
440
|
+
if self.state is not schemas.api_gateway.APIGatewayState.ready:
|
|
380
441
|
# try to sync the state
|
|
381
442
|
self.sync()
|
|
382
|
-
return self.state ==
|
|
443
|
+
return self.state == schemas.api_gateway.APIGatewayState.ready
|
|
383
444
|
|
|
384
445
|
def sync(self):
|
|
385
446
|
"""
|
|
@@ -407,16 +468,27 @@ class APIGateway(ModelObj):
|
|
|
407
468
|
"""
|
|
408
469
|
self.spec.authentication = BasicAuth(username=username, password=password)
|
|
409
470
|
|
|
471
|
+
@min_iguazio_versions("3.5.5")
|
|
472
|
+
def with_access_key_auth(self):
|
|
473
|
+
"""
|
|
474
|
+
Set access key authentication for the API gateway.
|
|
475
|
+
"""
|
|
476
|
+
self.spec.authentication = AccessKeyAuth()
|
|
477
|
+
|
|
410
478
|
def with_canary(
|
|
411
479
|
self,
|
|
412
480
|
functions: Union[
|
|
413
|
-
list[str],
|
|
414
481
|
list[
|
|
415
482
|
Union[
|
|
416
|
-
|
|
417
|
-
|
|
483
|
+
str,
|
|
484
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
485
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
486
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
418
487
|
]
|
|
419
488
|
],
|
|
489
|
+
"mlrun.runtimes.nuclio.function.RemoteRuntime",
|
|
490
|
+
"mlrun.runtimes.nuclio.serving.ServingRuntime",
|
|
491
|
+
"mlrun.runtimes.nuclio.application.ApplicationRuntime",
|
|
420
492
|
],
|
|
421
493
|
canary: list[int],
|
|
422
494
|
):
|
|
@@ -427,7 +499,8 @@ class APIGateway(ModelObj):
|
|
|
427
499
|
Can be a list of function names (["my-func1", "my-func2"])
|
|
428
500
|
or a list of nuclio functions of types
|
|
429
501
|
:py:class:`~mlrun.runtimes.nuclio.function.RemoteRuntime` OR
|
|
430
|
-
:py:class:`~mlrun.runtimes.nuclio.serving.ServingRuntime`
|
|
502
|
+
:py:class:`~mlrun.runtimes.nuclio.serving.ServingRuntime` OR
|
|
503
|
+
:py:class:`~mlrun.runtimes.nuclio.application.ApplicationRuntime`
|
|
431
504
|
:param canary: The canary percents for the API gateway of type list[int]; for instance: [20,80]
|
|
432
505
|
|
|
433
506
|
"""
|
|
@@ -440,14 +513,25 @@ class APIGateway(ModelObj):
|
|
|
440
513
|
project=self.spec.project, functions=functions, canary=canary
|
|
441
514
|
)
|
|
442
515
|
|
|
516
|
+
def with_ports(self, ports: list[int]):
|
|
517
|
+
"""
|
|
518
|
+
Set ports for the API gateway
|
|
519
|
+
|
|
520
|
+
:param ports: The ports of the API gateway, as a list of integers that correspond to the functions in the
|
|
521
|
+
functions list. for instance: [8050] or [8050, 8081]
|
|
522
|
+
"""
|
|
523
|
+
self.spec.validate(
|
|
524
|
+
project=self.spec.project, functions=self.spec.functions, ports=ports
|
|
525
|
+
)
|
|
526
|
+
|
|
443
527
|
@classmethod
|
|
444
|
-
def from_scheme(cls, api_gateway:
|
|
528
|
+
def from_scheme(cls, api_gateway: schemas.APIGateway):
|
|
445
529
|
project = api_gateway.metadata.labels.get(PROJECT_NAME_LABEL)
|
|
446
530
|
functions, canary = cls._resolve_canary(api_gateway.spec.upstreams)
|
|
447
531
|
state = (
|
|
448
532
|
api_gateway.status.state
|
|
449
533
|
if api_gateway.status
|
|
450
|
-
else
|
|
534
|
+
else schemas.APIGatewayState.none
|
|
451
535
|
)
|
|
452
536
|
new_api_gateway = cls(
|
|
453
537
|
metadata=APIGatewayMetadata(
|
|
@@ -466,14 +550,14 @@ class APIGateway(ModelObj):
|
|
|
466
550
|
new_api_gateway.state = state
|
|
467
551
|
return new_api_gateway
|
|
468
552
|
|
|
469
|
-
def to_scheme(self) ->
|
|
553
|
+
def to_scheme(self) -> schemas.APIGateway:
|
|
470
554
|
upstreams = (
|
|
471
555
|
[
|
|
472
|
-
|
|
556
|
+
schemas.APIGatewayUpstream(
|
|
473
557
|
nucliofunction={"name": self.spec.functions[0]},
|
|
474
558
|
percentage=self.spec.canary[0],
|
|
475
559
|
),
|
|
476
|
-
|
|
560
|
+
schemas.APIGatewayUpstream(
|
|
477
561
|
# do not set percent for the second function,
|
|
478
562
|
# so we can define which function to display as a primary one in UI
|
|
479
563
|
nucliofunction={"name": self.spec.functions[1]},
|
|
@@ -481,22 +565,24 @@ class APIGateway(ModelObj):
|
|
|
481
565
|
]
|
|
482
566
|
if self.spec.canary
|
|
483
567
|
else [
|
|
484
|
-
|
|
568
|
+
schemas.APIGatewayUpstream(
|
|
485
569
|
nucliofunction={"name": function_name},
|
|
486
570
|
)
|
|
487
571
|
for function_name in self.spec.functions
|
|
488
572
|
]
|
|
489
573
|
)
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
574
|
+
if self.spec.ports:
|
|
575
|
+
for i, port in enumerate(self.spec.ports):
|
|
576
|
+
upstreams[i].port = port
|
|
577
|
+
|
|
578
|
+
api_gateway = schemas.APIGateway(
|
|
579
|
+
metadata=schemas.APIGatewayMetadata(name=self.metadata.name, labels={}),
|
|
580
|
+
spec=schemas.APIGatewaySpec(
|
|
495
581
|
name=self.metadata.name,
|
|
496
582
|
description=self.spec.description,
|
|
497
583
|
host=self.spec.host,
|
|
498
584
|
path=self.spec.path,
|
|
499
|
-
authenticationMode=
|
|
585
|
+
authenticationMode=schemas.APIGatewayAuthenticationMode.from_str(
|
|
500
586
|
self.spec.authentication.authentication_mode
|
|
501
587
|
),
|
|
502
588
|
upstreams=upstreams,
|
|
@@ -526,7 +612,7 @@ class APIGateway(ModelObj):
|
|
|
526
612
|
|
|
527
613
|
@staticmethod
|
|
528
614
|
def _resolve_canary(
|
|
529
|
-
upstreams: list[
|
|
615
|
+
upstreams: list[schemas.APIGatewayUpstream],
|
|
530
616
|
) -> tuple[Union[list[str], None], Union[list[int], None]]:
|
|
531
617
|
if len(upstreams) == 1:
|
|
532
618
|
return [upstreams[0].nucliofunction.get("name")], None
|