mlrun 1.7.0rc4__py3-none-any.whl → 1.7.0rc5__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/common/constants.py +1 -0
- mlrun/common/schemas/__init__.py +10 -0
- mlrun/common/schemas/api_gateway.py +85 -0
- mlrun/common/schemas/auth.py +2 -2
- mlrun/config.py +11 -2
- mlrun/datastore/targets.py +16 -20
- mlrun/db/base.py +16 -0
- mlrun/db/httpdb.py +50 -8
- mlrun/db/nopdb.py +13 -0
- mlrun/projects/project.py +59 -0
- mlrun/run.py +1 -1
- mlrun/runtimes/base.py +14 -10
- mlrun/runtimes/nuclio/__init__.py +1 -0
- mlrun/runtimes/nuclio/api_gateway.py +300 -0
- mlrun/utils/logger.py +2 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc5.dist-info}/METADATA +1 -1
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc5.dist-info}/RECORD +22 -20
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc5.dist-info}/WHEEL +1 -1
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc5.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc5.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc5.dist-info}/top_level.txt +0 -0
mlrun/common/constants.py
CHANGED
mlrun/common/schemas/__init__.py
CHANGED
|
@@ -14,6 +14,16 @@
|
|
|
14
14
|
#
|
|
15
15
|
# flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
|
|
16
16
|
|
|
17
|
+
from .api_gateway import (
|
|
18
|
+
APIGateway,
|
|
19
|
+
APIGatewayAuthenticationMode,
|
|
20
|
+
APIGatewayBasicAuth,
|
|
21
|
+
APIGatewayMetadata,
|
|
22
|
+
APIGatewaysOutput,
|
|
23
|
+
APIGatewaySpec,
|
|
24
|
+
APIGatewayStatus,
|
|
25
|
+
APIGatewayUpstream,
|
|
26
|
+
)
|
|
17
27
|
from .artifact import (
|
|
18
28
|
Artifact,
|
|
19
29
|
ArtifactCategories,
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Copyright 2023 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
#
|
|
15
|
+
import typing
|
|
16
|
+
from typing import Optional
|
|
17
|
+
|
|
18
|
+
import pydantic
|
|
19
|
+
|
|
20
|
+
import mlrun.common.types
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class APIGatewayAuthenticationMode(mlrun.common.types.StrEnum):
|
|
24
|
+
basic = "basicAuth"
|
|
25
|
+
none = "none"
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def from_str(cls, authentication_mode: str):
|
|
29
|
+
if authentication_mode == "none":
|
|
30
|
+
return cls.none
|
|
31
|
+
elif authentication_mode == "basicAuth":
|
|
32
|
+
return cls.basic
|
|
33
|
+
else:
|
|
34
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
35
|
+
f"Authentication mode `{authentication_mode}` is not supported",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class _APIGatewayBaseModel(pydantic.BaseModel):
|
|
40
|
+
class Config:
|
|
41
|
+
extra = pydantic.Extra.allow
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class APIGatewayMetadata(_APIGatewayBaseModel):
|
|
45
|
+
name: str
|
|
46
|
+
namespace: Optional[str]
|
|
47
|
+
labels: Optional[dict] = {}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class APIGatewayBasicAuth(_APIGatewayBaseModel):
|
|
51
|
+
username: str
|
|
52
|
+
password: str
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class APIGatewayUpstream(_APIGatewayBaseModel):
|
|
56
|
+
kind: Optional[str] = "nucliofunction"
|
|
57
|
+
nucliofunction: dict[str, str]
|
|
58
|
+
percentage: Optional[int] = 0
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class APIGatewaySpec(_APIGatewayBaseModel):
|
|
62
|
+
name: str
|
|
63
|
+
description: Optional[str]
|
|
64
|
+
path: Optional[str] = "/"
|
|
65
|
+
authenticationMode: Optional[APIGatewayAuthenticationMode] = (
|
|
66
|
+
APIGatewayAuthenticationMode.none
|
|
67
|
+
)
|
|
68
|
+
upstreams: list[APIGatewayUpstream]
|
|
69
|
+
authentication: Optional[dict[str, Optional[APIGatewayBasicAuth]]]
|
|
70
|
+
host: Optional[str]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class APIGatewayStatus(_APIGatewayBaseModel):
|
|
74
|
+
name: Optional[str]
|
|
75
|
+
state: Optional[str]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class APIGateway(_APIGatewayBaseModel):
|
|
79
|
+
metadata: APIGatewayMetadata
|
|
80
|
+
spec: APIGatewaySpec
|
|
81
|
+
status: Optional[APIGatewayStatus]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class APIGatewaysOutput(_APIGatewayBaseModel):
|
|
85
|
+
api_gateways: typing.Optional[dict[str, APIGateway]] = {}
|
mlrun/common/schemas/auth.py
CHANGED
|
@@ -59,7 +59,7 @@ class AuthorizationResourceTypes(mlrun.common.types.StrEnum):
|
|
|
59
59
|
hub_source = "hub-source"
|
|
60
60
|
workflow = "workflow"
|
|
61
61
|
datastore_profile = "datastore-profile"
|
|
62
|
-
|
|
62
|
+
api_gateway = "api-gateway"
|
|
63
63
|
|
|
64
64
|
def to_resource_string(
|
|
65
65
|
self,
|
|
@@ -94,7 +94,7 @@ class AuthorizationResourceTypes(mlrun.common.types.StrEnum):
|
|
|
94
94
|
AuthorizationResourceTypes.hub_source: "/marketplace/sources",
|
|
95
95
|
# workflow define how to run a pipeline and can be considered as the specification of a pipeline.
|
|
96
96
|
AuthorizationResourceTypes.workflow: "/projects/{project_name}/workflows/{resource_name}",
|
|
97
|
-
AuthorizationResourceTypes.
|
|
97
|
+
AuthorizationResourceTypes.api_gateway: "/projects/{project_name}/api-gateways/{resource_name}",
|
|
98
98
|
}[self].format(project_name=project_name, resource_name=resource_name)
|
|
99
99
|
|
|
100
100
|
|
mlrun/config.py
CHANGED
|
@@ -1348,12 +1348,21 @@ def read_env(env=None, prefix=env_prefix):
|
|
|
1348
1348
|
if igz_domain:
|
|
1349
1349
|
config["ui_url"] = f"https://mlrun-ui.{igz_domain}"
|
|
1350
1350
|
|
|
1351
|
-
if config.get("log_level"):
|
|
1351
|
+
if log_level := config.get("log_level"):
|
|
1352
1352
|
import mlrun.utils.logger
|
|
1353
1353
|
|
|
1354
1354
|
# logger created (because of imports mess) before the config is loaded (in tests), therefore we're changing its
|
|
1355
1355
|
# level manually
|
|
1356
|
-
mlrun.utils.logger.set_logger_level(
|
|
1356
|
+
mlrun.utils.logger.set_logger_level(log_level)
|
|
1357
|
+
|
|
1358
|
+
if log_formatter_name := config.get("log_formatter"):
|
|
1359
|
+
import mlrun.utils.logger
|
|
1360
|
+
|
|
1361
|
+
log_formatter = mlrun.utils.create_formatter_instance(
|
|
1362
|
+
mlrun.utils.FormatterKinds(log_formatter_name)
|
|
1363
|
+
)
|
|
1364
|
+
mlrun.utils.logger.get_handler("default").setFormatter(log_formatter)
|
|
1365
|
+
|
|
1357
1366
|
# The default function pod resource values are of type str; however, when reading from environment variable numbers,
|
|
1358
1367
|
# it converts them to type int if contains only number, so we want to convert them to str.
|
|
1359
1368
|
_convert_resources_to_str(config)
|
mlrun/datastore/targets.py
CHANGED
|
@@ -451,7 +451,7 @@ class BaseStoreTarget(DataTargetBase):
|
|
|
451
451
|
self.get_target_path(),
|
|
452
452
|
credentials_prefix_secrets,
|
|
453
453
|
)
|
|
454
|
-
return store, url
|
|
454
|
+
return store, resolved_store_path, url
|
|
455
455
|
|
|
456
456
|
def _get_column_list(self, features, timestamp_key, key_columns, with_type=False):
|
|
457
457
|
result = []
|
|
@@ -500,7 +500,7 @@ class BaseStoreTarget(DataTargetBase):
|
|
|
500
500
|
write_spark_dataframe_with_options(options, df, "overwrite")
|
|
501
501
|
elif hasattr(df, "dask"):
|
|
502
502
|
dask_options = self.get_dask_options()
|
|
503
|
-
store, target_path = self._get_store_and_path()
|
|
503
|
+
store, path_in_store, target_path = self._get_store_and_path()
|
|
504
504
|
storage_options = store.get_storage_options()
|
|
505
505
|
df = df.repartition(partition_size="100MB")
|
|
506
506
|
try:
|
|
@@ -521,7 +521,7 @@ class BaseStoreTarget(DataTargetBase):
|
|
|
521
521
|
except Exception as exc:
|
|
522
522
|
raise RuntimeError("Failed to write Dask Dataframe") from exc
|
|
523
523
|
else:
|
|
524
|
-
store, target_path = self._get_store_and_path()
|
|
524
|
+
store, path_in_store, target_path = self._get_store_and_path()
|
|
525
525
|
target_path = generate_path_with_chunk(self, chunk_id, target_path)
|
|
526
526
|
file_system = store.filesystem
|
|
527
527
|
if file_system.protocol == "file":
|
|
@@ -688,7 +688,7 @@ class BaseStoreTarget(DataTargetBase):
|
|
|
688
688
|
raise NotImplementedError()
|
|
689
689
|
|
|
690
690
|
def purge(self):
|
|
691
|
-
store, target_path = self._get_store_and_path()
|
|
691
|
+
store, path_in_store, target_path = self._get_store_and_path()
|
|
692
692
|
store.rm(target_path, recursive=True)
|
|
693
693
|
|
|
694
694
|
def as_df(
|
|
@@ -868,7 +868,7 @@ class ParquetTarget(BaseStoreTarget):
|
|
|
868
868
|
for key_column in key_columns:
|
|
869
869
|
tuple_key_columns.append((key_column.name, key_column.value_type))
|
|
870
870
|
|
|
871
|
-
store, target_path = self._get_store_and_path()
|
|
871
|
+
store, path_in_store, target_path = self._get_store_and_path()
|
|
872
872
|
|
|
873
873
|
storage_options = store.get_storage_options()
|
|
874
874
|
if storage_options and self.storage_options:
|
|
@@ -921,9 +921,7 @@ class ParquetTarget(BaseStoreTarget):
|
|
|
921
921
|
if unit == time_partitioning_granularity:
|
|
922
922
|
break
|
|
923
923
|
|
|
924
|
-
store, path, url =
|
|
925
|
-
self.get_target_path()
|
|
926
|
-
)
|
|
924
|
+
store, path, url = self._get_store_and_path()
|
|
927
925
|
spark_options = store.get_spark_options()
|
|
928
926
|
spark_options.update(
|
|
929
927
|
{
|
|
@@ -1042,7 +1040,7 @@ class CSVTarget(BaseStoreTarget):
|
|
|
1042
1040
|
column_list = self._get_column_list(
|
|
1043
1041
|
features=features, timestamp_key=timestamp_key, key_columns=key_columns
|
|
1044
1042
|
)
|
|
1045
|
-
store, target_path = self._get_store_and_path()
|
|
1043
|
+
store, path_in_store, target_path = self._get_store_and_path()
|
|
1046
1044
|
graph.add_step(
|
|
1047
1045
|
name=self.name or "CSVTarget",
|
|
1048
1046
|
after=after,
|
|
@@ -1057,9 +1055,7 @@ class CSVTarget(BaseStoreTarget):
|
|
|
1057
1055
|
)
|
|
1058
1056
|
|
|
1059
1057
|
def get_spark_options(self, key_column=None, timestamp_key=None, overwrite=True):
|
|
1060
|
-
store, path, url =
|
|
1061
|
-
self.get_target_path()
|
|
1062
|
-
)
|
|
1058
|
+
store, path, url = self._get_store_and_path()
|
|
1063
1059
|
spark_options = store.get_spark_options()
|
|
1064
1060
|
spark_options.update(
|
|
1065
1061
|
{
|
|
@@ -1193,7 +1189,7 @@ class NoSqlBaseTarget(BaseStoreTarget):
|
|
|
1193
1189
|
df = df.copy(deep=False)
|
|
1194
1190
|
access_key = self._get_credential("V3IO_ACCESS_KEY")
|
|
1195
1191
|
|
|
1196
|
-
store, target_path = self._get_store_and_path()
|
|
1192
|
+
store, path_in_store, target_path = self._get_store_and_path()
|
|
1197
1193
|
storage_options = store.get_storage_options()
|
|
1198
1194
|
access_key = storage_options.get("v3io_access_key", access_key)
|
|
1199
1195
|
|
|
@@ -1215,7 +1211,7 @@ class NoSqlTarget(NoSqlBaseTarget):
|
|
|
1215
1211
|
def get_table_object(self):
|
|
1216
1212
|
from storey import Table, V3ioDriver
|
|
1217
1213
|
|
|
1218
|
-
store, target_path = self._get_store_and_path()
|
|
1214
|
+
store, path_in_store, target_path = self._get_store_and_path()
|
|
1219
1215
|
endpoint, uri = parse_path(target_path)
|
|
1220
1216
|
storage_options = store.get_storage_options()
|
|
1221
1217
|
access_key = storage_options.get("v3io_access_key")
|
|
@@ -1227,7 +1223,7 @@ class NoSqlTarget(NoSqlBaseTarget):
|
|
|
1227
1223
|
)
|
|
1228
1224
|
|
|
1229
1225
|
def get_spark_options(self, key_column=None, timestamp_key=None, overwrite=True):
|
|
1230
|
-
store, target_path = self._get_store_and_path()
|
|
1226
|
+
store, path_in_store, target_path = self._get_store_and_path()
|
|
1231
1227
|
storage_options = store.get_storage_options()
|
|
1232
1228
|
store_access_key = storage_options.get("v3io_access_key")
|
|
1233
1229
|
env_access_key = self._secrets.get(
|
|
@@ -1239,7 +1235,7 @@ class NoSqlTarget(NoSqlBaseTarget):
|
|
|
1239
1235
|
"Spark will disregard the store-provided key."
|
|
1240
1236
|
)
|
|
1241
1237
|
spark_options = {
|
|
1242
|
-
"path": store.spark_url +
|
|
1238
|
+
"path": store.spark_url + path_in_store,
|
|
1243
1239
|
"format": "io.iguaz.v3io.spark.sql.kv",
|
|
1244
1240
|
}
|
|
1245
1241
|
if isinstance(key_column, list) and len(key_column) >= 1:
|
|
@@ -1332,10 +1328,10 @@ class RedisNoSqlTarget(NoSqlBaseTarget):
|
|
|
1332
1328
|
def get_spark_options(self, key_column=None, timestamp_key=None, overwrite=True):
|
|
1333
1329
|
endpoint, uri = self._get_server_endpoint()
|
|
1334
1330
|
parsed_endpoint = urlparse(endpoint)
|
|
1335
|
-
store, path = self._get_store_and_path()
|
|
1331
|
+
store, path_in_store, path = self._get_store_and_path()
|
|
1336
1332
|
return {
|
|
1337
1333
|
"key.column": "_spark_object_name",
|
|
1338
|
-
"table": "{" +
|
|
1334
|
+
"table": "{" + path_in_store,
|
|
1339
1335
|
"format": "org.apache.spark.sql.redis",
|
|
1340
1336
|
"host": parsed_endpoint.hostname,
|
|
1341
1337
|
"port": parsed_endpoint.port,
|
|
@@ -1383,7 +1379,7 @@ class StreamTarget(BaseStoreTarget):
|
|
|
1383
1379
|
from storey import V3ioDriver
|
|
1384
1380
|
|
|
1385
1381
|
key_columns = list(key_columns.keys())
|
|
1386
|
-
store, path = self._get_store_and_path()
|
|
1382
|
+
store, path_in_store, path = self._get_store_and_path()
|
|
1387
1383
|
if not path:
|
|
1388
1384
|
raise mlrun.errors.MLRunInvalidArgumentError("StreamTarget requires a path")
|
|
1389
1385
|
endpoint, uri = parse_path(path)
|
|
@@ -1537,7 +1533,7 @@ class TSDBTarget(BaseStoreTarget):
|
|
|
1537
1533
|
key_column = [key_column]
|
|
1538
1534
|
new_index.extend(key_column)
|
|
1539
1535
|
|
|
1540
|
-
store, target_path = self._get_store_and_path()
|
|
1536
|
+
store, path_in_store, target_path = self._get_store_and_path()
|
|
1541
1537
|
storage_options = store.get_storage_options()
|
|
1542
1538
|
access_key = storage_options.get("v3io_access_key", access_key)
|
|
1543
1539
|
|
mlrun/db/base.py
CHANGED
|
@@ -616,6 +616,22 @@ class RunDBInterface(ABC):
|
|
|
616
616
|
):
|
|
617
617
|
pass
|
|
618
618
|
|
|
619
|
+
@abstractmethod
|
|
620
|
+
def store_api_gateway(
|
|
621
|
+
self,
|
|
622
|
+
project: str,
|
|
623
|
+
api_gateway: mlrun.common.schemas.APIGateway,
|
|
624
|
+
):
|
|
625
|
+
pass
|
|
626
|
+
|
|
627
|
+
@abstractmethod
|
|
628
|
+
def list_api_gateways(self, project=None) -> mlrun.common.schemas.APIGatewaysOutput:
|
|
629
|
+
pass
|
|
630
|
+
|
|
631
|
+
@abstractmethod
|
|
632
|
+
def get_api_gateway(self, name, project=None) -> mlrun.common.schemas.APIGateway:
|
|
633
|
+
pass
|
|
634
|
+
|
|
619
635
|
def get_builder_status(
|
|
620
636
|
self,
|
|
621
637
|
func: "mlrun.runtimes.BaseRuntime",
|
mlrun/db/httpdb.py
CHANGED
|
@@ -33,6 +33,7 @@ import mlrun.common.schemas
|
|
|
33
33
|
import mlrun.model_monitoring.model_endpoint
|
|
34
34
|
import mlrun.platforms
|
|
35
35
|
import mlrun.projects
|
|
36
|
+
import mlrun.runtimes.nuclio.api_gateway
|
|
36
37
|
from mlrun.errors import MLRunInvalidArgumentError, err_to_str
|
|
37
38
|
|
|
38
39
|
from ..artifacts import Artifact
|
|
@@ -3369,20 +3370,61 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3369
3370
|
body=dict_to_json(authorization_verification_input.dict()),
|
|
3370
3371
|
)
|
|
3371
3372
|
|
|
3372
|
-
def list_api_gateways(self, project=None):
|
|
3373
|
+
def list_api_gateways(self, project=None) -> mlrun.common.schemas.APIGatewaysOutput:
|
|
3373
3374
|
"""
|
|
3374
3375
|
Returns a list of Nuclio api gateways
|
|
3375
|
-
:param project: optional str parameter to filter by project, if not passed, default
|
|
3376
|
+
:param project: optional str parameter to filter by project, if not passed, default project value is taken
|
|
3376
3377
|
|
|
3377
|
-
:return:
|
|
3378
|
-
(json example is here
|
|
3379
|
-
https://github.com/nuclio/nuclio/blob/development/docs/reference/api/README.md#listing-all-api-gateways)
|
|
3378
|
+
:return: :py:class:`~mlrun.common.schemas.APIGateways`.
|
|
3380
3379
|
"""
|
|
3381
3380
|
project = project or config.default_project
|
|
3382
3381
|
error = "list api gateways"
|
|
3383
|
-
endpoint_path = f"projects/{project}/
|
|
3384
|
-
|
|
3385
|
-
return
|
|
3382
|
+
endpoint_path = f"projects/{project}/api-gateways"
|
|
3383
|
+
response = self.api_call("GET", endpoint_path, error)
|
|
3384
|
+
return mlrun.common.schemas.APIGatewaysOutput(**response.json())
|
|
3385
|
+
|
|
3386
|
+
def get_api_gateway(self, name, project=None) -> mlrun.common.schemas.APIGateway:
|
|
3387
|
+
"""
|
|
3388
|
+
Returns an API gateway
|
|
3389
|
+
:param name: API gateway name
|
|
3390
|
+
:param project: optional str parameter to filter by project, if not passed, default project value is taken
|
|
3391
|
+
|
|
3392
|
+
:return: :py:class:`~mlrun.common.schemas.APIGateway`.
|
|
3393
|
+
"""
|
|
3394
|
+
project = project or config.default_project
|
|
3395
|
+
error = "get api gateway"
|
|
3396
|
+
endpoint_path = f"projects/{project}/api-gateways/{name}"
|
|
3397
|
+
response = self.api_call("GET", endpoint_path, error)
|
|
3398
|
+
return mlrun.common.schemas.APIGateway(**response.json())
|
|
3399
|
+
|
|
3400
|
+
def store_api_gateway(
|
|
3401
|
+
self,
|
|
3402
|
+
api_gateway: Union[
|
|
3403
|
+
mlrun.common.schemas.APIGateway,
|
|
3404
|
+
mlrun.runtimes.nuclio.api_gateway.APIGateway,
|
|
3405
|
+
],
|
|
3406
|
+
project: Optional[str] = None,
|
|
3407
|
+
) -> mlrun.common.schemas.APIGateway:
|
|
3408
|
+
"""
|
|
3409
|
+
Stores an API Gateway.
|
|
3410
|
+
:param api_gateway :py:class:`~mlrun.runtimes.nuclio.APIGateway`
|
|
3411
|
+
or :py:class:`~mlrun.common.schemas.APIGateway`: API Gateway entity.
|
|
3412
|
+
:param project: project name. Mandatory if api_gateway is mlrun.common.schemas.APIGateway.
|
|
3413
|
+
|
|
3414
|
+
:return: :py:class:`~mlrun.common.schemas.APIGateway`.
|
|
3415
|
+
"""
|
|
3416
|
+
|
|
3417
|
+
if isinstance(api_gateway, mlrun.runtimes.nuclio.api_gateway.APIGateway):
|
|
3418
|
+
api_gateway = api_gateway.to_scheme()
|
|
3419
|
+
endpoint_path = f"projects/{project}/api-gateways/{api_gateway.metadata.name}"
|
|
3420
|
+
error = "store api gateways"
|
|
3421
|
+
response = self.api_call(
|
|
3422
|
+
"PUT",
|
|
3423
|
+
endpoint_path,
|
|
3424
|
+
error,
|
|
3425
|
+
json=api_gateway.dict(exclude_unset=True, exclude_none=True),
|
|
3426
|
+
)
|
|
3427
|
+
return mlrun.common.schemas.APIGateway(**response.json())
|
|
3386
3428
|
|
|
3387
3429
|
def trigger_migrations(self) -> Optional[mlrun.common.schemas.BackgroundTask]:
|
|
3388
3430
|
"""Trigger migrations (will do nothing if no migrations are needed) and wait for them to finish if actually
|
mlrun/db/nopdb.py
CHANGED
|
@@ -506,6 +506,19 @@ class NopDB(RunDBInterface):
|
|
|
506
506
|
):
|
|
507
507
|
pass
|
|
508
508
|
|
|
509
|
+
def store_api_gateway(
|
|
510
|
+
self,
|
|
511
|
+
project: str,
|
|
512
|
+
api_gateway: mlrun.runtimes.nuclio.APIGateway,
|
|
513
|
+
) -> mlrun.common.schemas.APIGateway:
|
|
514
|
+
pass
|
|
515
|
+
|
|
516
|
+
def list_api_gateways(self, project=None):
|
|
517
|
+
pass
|
|
518
|
+
|
|
519
|
+
def get_api_gateway(self, name, project=None):
|
|
520
|
+
pass
|
|
521
|
+
|
|
509
522
|
def verify_authorization(
|
|
510
523
|
self,
|
|
511
524
|
authorization_verification_input: mlrun.common.schemas.AuthorizationVerificationInput,
|
mlrun/projects/project.py
CHANGED
|
@@ -41,6 +41,7 @@ import mlrun.db
|
|
|
41
41
|
import mlrun.errors
|
|
42
42
|
import mlrun.k8s_utils
|
|
43
43
|
import mlrun.runtimes
|
|
44
|
+
import mlrun.runtimes.nuclio.api_gateway
|
|
44
45
|
import mlrun.runtimes.pod
|
|
45
46
|
import mlrun.runtimes.utils
|
|
46
47
|
import mlrun.utils.regex
|
|
@@ -3625,6 +3626,64 @@ class MlrunProject(ModelObj):
|
|
|
3625
3626
|
"""
|
|
3626
3627
|
self.spec.remove_custom_packager(packager=packager)
|
|
3627
3628
|
|
|
3629
|
+
def store_api_gateway(
|
|
3630
|
+
self, api_gateway: mlrun.runtimes.nuclio.api_gateway.APIGateway
|
|
3631
|
+
) -> mlrun.runtimes.nuclio.api_gateway.APIGateway:
|
|
3632
|
+
"""
|
|
3633
|
+
Creates or updates a Nuclio API Gateway using the provided APIGateway object.
|
|
3634
|
+
|
|
3635
|
+
This method interacts with the MLRun service to create/update a Nuclio API Gateway based on the provided
|
|
3636
|
+
APIGateway object. Once done, it returns the updated APIGateway object containing all fields propagated
|
|
3637
|
+
on MLRun and Nuclio sides, such as the 'host' attribute.
|
|
3638
|
+
Nuclio docs here: https://docs.nuclio.io/en/latest/reference/api-gateway/http.html
|
|
3639
|
+
|
|
3640
|
+
:param api_gateway: An instance of :py:class:`~mlrun.runtimes.nuclio.APIGateway` representing the configuration
|
|
3641
|
+
of the API Gateway to be created
|
|
3642
|
+
|
|
3643
|
+
@return: An instance of :py:class:`~mlrun.runtimes.nuclio.APIGateway` with all fields populated based on the
|
|
3644
|
+
information retrieved from the Nuclio API
|
|
3645
|
+
"""
|
|
3646
|
+
|
|
3647
|
+
api_gateway_json = mlrun.db.get_run_db().store_api_gateway(
|
|
3648
|
+
api_gateway=api_gateway,
|
|
3649
|
+
project=self.name,
|
|
3650
|
+
)
|
|
3651
|
+
|
|
3652
|
+
if api_gateway_json:
|
|
3653
|
+
# fill in all the fields in the user's api_gateway object
|
|
3654
|
+
api_gateway = mlrun.runtimes.nuclio.api_gateway.APIGateway.from_scheme(
|
|
3655
|
+
api_gateway_json
|
|
3656
|
+
)
|
|
3657
|
+
return api_gateway
|
|
3658
|
+
|
|
3659
|
+
def list_api_gateways(self) -> list[mlrun.runtimes.nuclio.api_gateway.APIGateway]:
|
|
3660
|
+
"""
|
|
3661
|
+
Retrieves a list of Nuclio API gateways associated with the project.
|
|
3662
|
+
|
|
3663
|
+
@return: List of :py:class:`~mlrun.runtimes.nuclio.api_gateway.APIGateway` objects representing
|
|
3664
|
+
the Nuclio API gateways associated with the project.
|
|
3665
|
+
"""
|
|
3666
|
+
gateways_list = mlrun.db.get_run_db().list_api_gateways(self.name)
|
|
3667
|
+
return [
|
|
3668
|
+
mlrun.runtimes.nuclio.api_gateway.APIGateway.from_scheme(gateway_dict)
|
|
3669
|
+
for gateway_dict in gateways_list.api_gateways.values()
|
|
3670
|
+
]
|
|
3671
|
+
|
|
3672
|
+
def get_api_gateway(
|
|
3673
|
+
self,
|
|
3674
|
+
name: str,
|
|
3675
|
+
) -> mlrun.runtimes.nuclio.api_gateway.APIGateway:
|
|
3676
|
+
"""
|
|
3677
|
+
Retrieves an API gateway by name instance.
|
|
3678
|
+
|
|
3679
|
+
:param name: The name of the API gateway to retrieve.
|
|
3680
|
+
|
|
3681
|
+
Returns:
|
|
3682
|
+
mlrun.runtimes.nuclio.APIGateway: An instance of APIGateway.
|
|
3683
|
+
"""
|
|
3684
|
+
|
|
3685
|
+
return mlrun.db.get_run_db().get_api_gateway(name=name, project=self.name)
|
|
3686
|
+
|
|
3628
3687
|
def _run_authenticated_git_action(
|
|
3629
3688
|
self,
|
|
3630
3689
|
action: Callable,
|
mlrun/run.py
CHANGED
|
@@ -628,7 +628,7 @@ def code_to_function(
|
|
|
628
628
|
- spark: run distributed Spark job using Spark Kubernetes Operator
|
|
629
629
|
- remote-spark: run distributed Spark job on remote Spark service
|
|
630
630
|
|
|
631
|
-
Learn more about
|
|
631
|
+
Learn more about [Kinds of function (runtimes)](../concepts/functions-overview.html).
|
|
632
632
|
|
|
633
633
|
:param name: function name, typically best to use hyphen-case
|
|
634
634
|
:param project: project used to namespace the function, defaults to 'default'
|
mlrun/runtimes/base.py
CHANGED
|
@@ -138,20 +138,24 @@ class FunctionSpec(ModelObj):
|
|
|
138
138
|
|
|
139
139
|
@property
|
|
140
140
|
def clone_target_dir(self):
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
141
|
+
# TODO: remove this property in 1.9.0
|
|
142
|
+
if self.build.source_code_target_dir:
|
|
143
|
+
warnings.warn(
|
|
144
|
+
"The clone_target_dir attribute is deprecated in 1.6.2 and will be removed in 1.9.0. "
|
|
145
|
+
"Use spec.build.source_code_target_dir instead.",
|
|
146
|
+
FutureWarning,
|
|
147
|
+
)
|
|
146
148
|
return self.build.source_code_target_dir
|
|
147
149
|
|
|
148
150
|
@clone_target_dir.setter
|
|
149
151
|
def clone_target_dir(self, clone_target_dir):
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
# TODO: remove this property in 1.9.0
|
|
153
|
+
if clone_target_dir:
|
|
154
|
+
warnings.warn(
|
|
155
|
+
"The clone_target_dir attribute is deprecated in 1.6.2 and will be removed in 1.9.0. "
|
|
156
|
+
"Use spec.build.source_code_target_dir instead.",
|
|
157
|
+
FutureWarning,
|
|
158
|
+
)
|
|
155
159
|
self.build.source_code_target_dir = clone_target_dir
|
|
156
160
|
|
|
157
161
|
def enrich_function_preemption_spec(self):
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# Copyright 2023 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
import base64
|
|
15
|
+
from typing import Optional, Union
|
|
16
|
+
from urllib.parse import urljoin
|
|
17
|
+
|
|
18
|
+
import requests
|
|
19
|
+
|
|
20
|
+
import mlrun
|
|
21
|
+
import mlrun.common.schemas
|
|
22
|
+
|
|
23
|
+
from .function import RemoteRuntime
|
|
24
|
+
from .serving import ServingRuntime
|
|
25
|
+
|
|
26
|
+
NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH = "basicAuth"
|
|
27
|
+
NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_NONE = "none"
|
|
28
|
+
PROJECT_NAME_LABEL = "nuclio.io/project-name"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class APIGateway:
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
project,
|
|
35
|
+
name: str,
|
|
36
|
+
functions: Union[
|
|
37
|
+
list[str],
|
|
38
|
+
Union[
|
|
39
|
+
list[
|
|
40
|
+
Union[
|
|
41
|
+
RemoteRuntime,
|
|
42
|
+
ServingRuntime,
|
|
43
|
+
]
|
|
44
|
+
],
|
|
45
|
+
Union[RemoteRuntime, ServingRuntime],
|
|
46
|
+
],
|
|
47
|
+
],
|
|
48
|
+
description: str = "",
|
|
49
|
+
path: str = "/",
|
|
50
|
+
authentication_mode: Optional[
|
|
51
|
+
str
|
|
52
|
+
] = NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_NONE,
|
|
53
|
+
host: Optional[str] = None,
|
|
54
|
+
canary: Optional[list[int]] = None,
|
|
55
|
+
username: Optional[str] = None,
|
|
56
|
+
password: Optional[str] = None,
|
|
57
|
+
):
|
|
58
|
+
self.functions = None
|
|
59
|
+
self._validate(
|
|
60
|
+
project=project,
|
|
61
|
+
functions=functions,
|
|
62
|
+
name=name,
|
|
63
|
+
canary=canary,
|
|
64
|
+
username=username,
|
|
65
|
+
password=password,
|
|
66
|
+
)
|
|
67
|
+
self.project = project
|
|
68
|
+
self.name = name
|
|
69
|
+
self.host = host
|
|
70
|
+
|
|
71
|
+
self.path = path
|
|
72
|
+
self.description = description
|
|
73
|
+
self.authentication_mode = (
|
|
74
|
+
authentication_mode
|
|
75
|
+
if authentication_mode
|
|
76
|
+
else self._enrich_authentication_mode(username=username, password=password)
|
|
77
|
+
)
|
|
78
|
+
self.canary = canary
|
|
79
|
+
self._username = username
|
|
80
|
+
self._password = password
|
|
81
|
+
|
|
82
|
+
def invoke(
|
|
83
|
+
self,
|
|
84
|
+
method="POST",
|
|
85
|
+
headers: dict = {},
|
|
86
|
+
auth: Optional[tuple[str, str]] = None,
|
|
87
|
+
**kwargs,
|
|
88
|
+
):
|
|
89
|
+
if not self.invoke_url:
|
|
90
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
91
|
+
"Invocation url is not set. Set up gateway's `invoke_url` attribute."
|
|
92
|
+
)
|
|
93
|
+
if (
|
|
94
|
+
self.authentication_mode
|
|
95
|
+
== NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH
|
|
96
|
+
and not auth
|
|
97
|
+
):
|
|
98
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
99
|
+
"API Gateway invocation requires authentication. Please pass credentials"
|
|
100
|
+
)
|
|
101
|
+
if auth:
|
|
102
|
+
headers["Authorization"] = self._generate_basic_auth(*auth)
|
|
103
|
+
return requests.request(
|
|
104
|
+
method=method, url=self.invoke_url, headers=headers, **kwargs
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
@classmethod
|
|
108
|
+
def from_scheme(cls, api_gateway: mlrun.common.schemas.APIGateway):
|
|
109
|
+
project = api_gateway.metadata.labels.get(PROJECT_NAME_LABEL)
|
|
110
|
+
functions, canary = cls._resolve_canary(api_gateway.spec.upstreams)
|
|
111
|
+
return cls(
|
|
112
|
+
project=project,
|
|
113
|
+
description=api_gateway.spec.description,
|
|
114
|
+
name=api_gateway.spec.name,
|
|
115
|
+
host=api_gateway.spec.host,
|
|
116
|
+
path=api_gateway.spec.path,
|
|
117
|
+
authentication_mode=str(api_gateway.spec.authenticationMode),
|
|
118
|
+
functions=functions,
|
|
119
|
+
canary=canary,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def to_scheme(self) -> mlrun.common.schemas.APIGateway:
|
|
123
|
+
upstreams = (
|
|
124
|
+
[
|
|
125
|
+
mlrun.common.schemas.APIGatewayUpstream(
|
|
126
|
+
nucliofunction={"name": function_name},
|
|
127
|
+
percentage=percentage,
|
|
128
|
+
)
|
|
129
|
+
for function_name, percentage in zip(self.functions, self.canary)
|
|
130
|
+
]
|
|
131
|
+
if self.canary
|
|
132
|
+
else [
|
|
133
|
+
mlrun.common.schemas.APIGatewayUpstream(
|
|
134
|
+
nucliofunction={"name": function_name},
|
|
135
|
+
)
|
|
136
|
+
for function_name in self.functions
|
|
137
|
+
]
|
|
138
|
+
)
|
|
139
|
+
api_gateway = mlrun.common.schemas.APIGateway(
|
|
140
|
+
metadata=mlrun.common.schemas.APIGatewayMetadata(name=self.name, labels={}),
|
|
141
|
+
spec=mlrun.common.schemas.APIGatewaySpec(
|
|
142
|
+
name=self.name,
|
|
143
|
+
description=self.description,
|
|
144
|
+
path=self.path,
|
|
145
|
+
authentication_mode=mlrun.common.schemas.APIGatewayAuthenticationMode.from_str(
|
|
146
|
+
self.authentication_mode
|
|
147
|
+
),
|
|
148
|
+
upstreams=upstreams,
|
|
149
|
+
),
|
|
150
|
+
)
|
|
151
|
+
if (
|
|
152
|
+
self.authentication_mode
|
|
153
|
+
is NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH
|
|
154
|
+
):
|
|
155
|
+
api_gateway.spec.authentication = mlrun.common.schemas.APIGatewayBasicAuth(
|
|
156
|
+
username=self._username, password=self._password
|
|
157
|
+
)
|
|
158
|
+
return api_gateway
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def invoke_url(
|
|
162
|
+
self,
|
|
163
|
+
):
|
|
164
|
+
return urljoin(self.host, self.path)
|
|
165
|
+
|
|
166
|
+
def _validate(
|
|
167
|
+
self,
|
|
168
|
+
name: str,
|
|
169
|
+
project: str,
|
|
170
|
+
functions: Union[
|
|
171
|
+
list[str],
|
|
172
|
+
Union[
|
|
173
|
+
list[
|
|
174
|
+
Union[
|
|
175
|
+
RemoteRuntime,
|
|
176
|
+
ServingRuntime,
|
|
177
|
+
]
|
|
178
|
+
],
|
|
179
|
+
Union[RemoteRuntime, ServingRuntime],
|
|
180
|
+
],
|
|
181
|
+
],
|
|
182
|
+
canary: Optional[list[int]] = None,
|
|
183
|
+
username: Optional[str] = None,
|
|
184
|
+
password: Optional[str] = None,
|
|
185
|
+
):
|
|
186
|
+
if not name:
|
|
187
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
188
|
+
"API Gateway name cannot be empty"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
self.functions = self._validate_functions(project=project, functions=functions)
|
|
192
|
+
|
|
193
|
+
# validating canary
|
|
194
|
+
if canary:
|
|
195
|
+
if len(self.functions) != len(canary):
|
|
196
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
197
|
+
"Function and canary lists lengths do not match"
|
|
198
|
+
)
|
|
199
|
+
for canary_percent in canary:
|
|
200
|
+
if canary_percent < 0 or canary_percent > 100:
|
|
201
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
202
|
+
"The percentage value must be in the range from 0 to 100"
|
|
203
|
+
)
|
|
204
|
+
if sum(canary) != 100:
|
|
205
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
206
|
+
"The sum of canary function percents should be equal to 100"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# validating auth
|
|
210
|
+
if username and not password:
|
|
211
|
+
raise mlrun.errors.MLRunInvalidArgumentError("Password is not specified")
|
|
212
|
+
|
|
213
|
+
if password and not username:
|
|
214
|
+
raise mlrun.errors.MLRunInvalidArgumentError("Username is not specified")
|
|
215
|
+
|
|
216
|
+
@staticmethod
|
|
217
|
+
def _validate_functions(
|
|
218
|
+
project: str,
|
|
219
|
+
functions: Union[
|
|
220
|
+
list[str],
|
|
221
|
+
Union[
|
|
222
|
+
list[
|
|
223
|
+
Union[
|
|
224
|
+
RemoteRuntime,
|
|
225
|
+
ServingRuntime,
|
|
226
|
+
]
|
|
227
|
+
],
|
|
228
|
+
Union[RemoteRuntime, ServingRuntime],
|
|
229
|
+
],
|
|
230
|
+
],
|
|
231
|
+
):
|
|
232
|
+
if not isinstance(functions, list):
|
|
233
|
+
functions = [functions]
|
|
234
|
+
|
|
235
|
+
# validating functions
|
|
236
|
+
if not 1 <= len(functions) <= 2:
|
|
237
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
238
|
+
f"Gateway can be created from one or two functions, "
|
|
239
|
+
f"the number of functions passed is {len(functions)}"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
function_names = []
|
|
243
|
+
for func in functions:
|
|
244
|
+
if isinstance(func, str):
|
|
245
|
+
function_names.append(func)
|
|
246
|
+
continue
|
|
247
|
+
|
|
248
|
+
function_name = (
|
|
249
|
+
func.metadata.name if hasattr(func, "metadata") else func.name
|
|
250
|
+
)
|
|
251
|
+
if func.kind not in mlrun.runtimes.RuntimeKinds.nuclio_runtimes():
|
|
252
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
253
|
+
f"Input function {function_name} is not a Nuclio function"
|
|
254
|
+
)
|
|
255
|
+
if func.metadata.project != project:
|
|
256
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
257
|
+
f"input function {function_name} "
|
|
258
|
+
f"does not belong to this project"
|
|
259
|
+
)
|
|
260
|
+
function_names.append(func.uri)
|
|
261
|
+
return function_names
|
|
262
|
+
|
|
263
|
+
@staticmethod
|
|
264
|
+
def _enrich_authentication_mode(username, password):
|
|
265
|
+
return (
|
|
266
|
+
NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_NONE
|
|
267
|
+
if username is not None and password is not None
|
|
268
|
+
else NUCLIO_API_GATEWAY_AUTHENTICATION_MODE_BASIC_AUTH
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
@staticmethod
|
|
272
|
+
def _generate_basic_auth(username: str, password: str):
|
|
273
|
+
token = base64.b64encode(f"{username}:{password}".encode()).decode()
|
|
274
|
+
return f"Basic {token}"
|
|
275
|
+
|
|
276
|
+
@staticmethod
|
|
277
|
+
def _resolve_canary(
|
|
278
|
+
upstreams: list[mlrun.common.schemas.APIGatewayUpstream],
|
|
279
|
+
) -> tuple[Union[list[str], None], Union[list[int], None]]:
|
|
280
|
+
if len(upstreams) == 1:
|
|
281
|
+
return [upstreams[0].nucliofunction.get("name")], None
|
|
282
|
+
elif len(upstreams) == 2:
|
|
283
|
+
canary = [0, 0]
|
|
284
|
+
functions = [
|
|
285
|
+
upstreams[0].nucliofunction.get("name"),
|
|
286
|
+
upstreams[1].nucliofunction.get("name"),
|
|
287
|
+
]
|
|
288
|
+
percentage_1 = upstreams[0].percentage
|
|
289
|
+
percentage_2 = upstreams[1].percentage
|
|
290
|
+
|
|
291
|
+
if not percentage_1 and percentage_2:
|
|
292
|
+
percentage_1 = 100 - percentage_2
|
|
293
|
+
if not percentage_2 and percentage_1:
|
|
294
|
+
percentage_2 = 100 - percentage_1
|
|
295
|
+
if percentage_1 and percentage_2:
|
|
296
|
+
canary = [percentage_1, percentage_2]
|
|
297
|
+
return functions, canary
|
|
298
|
+
else:
|
|
299
|
+
# Nuclio only supports 1 or 2 upstream functions
|
|
300
|
+
return None, None
|
mlrun/utils/logger.py
CHANGED
|
@@ -221,7 +221,7 @@ class FormatterKinds(Enum):
|
|
|
221
221
|
JSON = "json"
|
|
222
222
|
|
|
223
223
|
|
|
224
|
-
def
|
|
224
|
+
def create_formatter_instance(formatter_kind: FormatterKinds) -> logging.Formatter:
|
|
225
225
|
return {
|
|
226
226
|
FormatterKinds.HUMAN: HumanReadableFormatter(),
|
|
227
227
|
FormatterKinds.HUMAN_EXTENDED: HumanReadableExtendedFormatter(),
|
|
@@ -243,7 +243,7 @@ def create_logger(
|
|
|
243
243
|
logger_instance = Logger(level, name=name, propagate=False)
|
|
244
244
|
|
|
245
245
|
# resolve formatter
|
|
246
|
-
formatter_instance =
|
|
246
|
+
formatter_instance = create_formatter_instance(
|
|
247
247
|
FormatterKinds(formatter_kind.lower())
|
|
248
248
|
)
|
|
249
249
|
|
mlrun/utils/version/version.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
mlrun/__init__.py,sha256=o9dHUfVFADfsi6GnOPLr2OkfkHdPvOnA7rkoECen0-I,7248
|
|
2
2
|
mlrun/__main__.py,sha256=vg-HMhJqQ3OYt31YmijjBh6-6AZQVe4FvDYn4MwEpYs,49229
|
|
3
|
-
mlrun/config.py,sha256=
|
|
3
|
+
mlrun/config.py,sha256=mAhLKO6P0i8r_vGDCMNFV0cJv4Pb7mRmm9HR3rudwWI,62563
|
|
4
4
|
mlrun/errors.py,sha256=HmOAdfpL0bCDisZMUoJPOumneq71ko49Ph-XBL-A4xA,7080
|
|
5
5
|
mlrun/execution.py,sha256=meZ_qSdTmnpqW7DKv7LdBmuE1Ut34E1RbK2kO0MD_QM,40866
|
|
6
6
|
mlrun/features.py,sha256=nPDvy8tJuxwbRr843oWcnLBrqMJDPUanzn2Sb3BBi6w,15569
|
|
@@ -9,7 +9,7 @@ mlrun/kfpops.py,sha256=nVQUjLVBhXqkL2OTWJUo4qFIfNVEXUKIXJmRpBW0MVU,30481
|
|
|
9
9
|
mlrun/lists.py,sha256=ev-gLBPc_az03yQEHrKyDPq_Bjosa4D_XFiVbRIpmRY,8286
|
|
10
10
|
mlrun/model.py,sha256=e9tJG8-wP3gPywDu7wJMNsusLTGpVA9WpBbILFwR5Ns,70583
|
|
11
11
|
mlrun/render.py,sha256=aMH3U2z7ELpW8MwYEGOrqLdEUwMX29shqy6V6-KbgiM,13009
|
|
12
|
-
mlrun/run.py,sha256=
|
|
12
|
+
mlrun/run.py,sha256=1GZk2f3xU2OrBE4aHMzVe0RUpwc1DokWiVwdwnTszlU,42400
|
|
13
13
|
mlrun/secrets.py,sha256=Nl_7ZNSErd-AOH19vVx_PjrLg9bJM9L-BvEYoPolB1c,7776
|
|
14
14
|
mlrun/api/schemas/__init__.py,sha256=LhfO3myrnLVxC0MYCAc1_LTuqhRlYV3H7BwJkjOu3dQ,14211
|
|
15
15
|
mlrun/artifacts/__init__.py,sha256=LxEWcMYPawJYvNOl6H2_UvrxdLTNYfKeZcMEKFZnGgA,1187
|
|
@@ -19,7 +19,7 @@ mlrun/artifacts/manager.py,sha256=p6CmIJH91vm9DsEZHgHxKYTHU2BvF9IwpLv85cqoHNs,14
|
|
|
19
19
|
mlrun/artifacts/model.py,sha256=DXT24CH1ZgQLz9HcWBfjRAEhCBfznoa7-pB52N9qMOI,25205
|
|
20
20
|
mlrun/artifacts/plots.py,sha256=dHt7Ardo4yZWaPtlUN3b78eB8NXV8XKigPP0u0poRl0,15701
|
|
21
21
|
mlrun/common/__init__.py,sha256=xY3wHC4TEJgez7qtnn1pQvHosi8-5UJOCtyGBS7FcGE,571
|
|
22
|
-
mlrun/common/constants.py,sha256=
|
|
22
|
+
mlrun/common/constants.py,sha256=OwcN3HroG3l94Kx1B-247cp1UyqC0IVLc_TCFGWmrg4,745
|
|
23
23
|
mlrun/common/helpers.py,sha256=BAhyuUnZvD_BT43i0_1EszuSbKgZx7bFy2KRIWP0XeA,1087
|
|
24
24
|
mlrun/common/secrets.py,sha256=vc8WV82EZsCB5ENjUkObFOzZP59aZ1w8F82PTnqwBnc,5181
|
|
25
25
|
mlrun/common/types.py,sha256=V_jCEFCJZcycFVsPzEToCRQja5bqW0zRAAVaGN_QYxQ,790
|
|
@@ -27,9 +27,10 @@ mlrun/common/db/__init__.py,sha256=xY3wHC4TEJgez7qtnn1pQvHosi8-5UJOCtyGBS7FcGE,5
|
|
|
27
27
|
mlrun/common/db/sql_session.py,sha256=Znc8KE2oLy4lg3_vRki1sVlNx59TgDSOTCXfU561hBU,2659
|
|
28
28
|
mlrun/common/model_monitoring/__init__.py,sha256=x0EMEvxVjHsm858J1t6IEA9dtKTdFpJ9sKhss10ld8A,721
|
|
29
29
|
mlrun/common/model_monitoring/helpers.py,sha256=1CpxIDQPumFnpUB1eqcvCpLlyPFVeW2sL6prM-N5A1A,4405
|
|
30
|
-
mlrun/common/schemas/__init__.py,sha256=
|
|
30
|
+
mlrun/common/schemas/__init__.py,sha256=PKOeaerKRHOIWCmaIhCYdlieOZhZDDf8cubNOWlJQaM,4935
|
|
31
|
+
mlrun/common/schemas/api_gateway.py,sha256=lDXnA0mE9PCyeB0p7VSoj7TN0xSF-e6XUrTYJjLqbbQ,2344
|
|
31
32
|
mlrun/common/schemas/artifact.py,sha256=d6srME_eWn2MpGuqvPQZtePRFkjDfNJgQ6JDd51qVrI,2796
|
|
32
|
-
mlrun/common/schemas/auth.py,sha256=
|
|
33
|
+
mlrun/common/schemas/auth.py,sha256=KOQfABIXTrcMh3Us5vlmnN4w3bJB7Rl3Xd5GTAFpr-g,5970
|
|
33
34
|
mlrun/common/schemas/background_task.py,sha256=2qZxib2qrF_nPZj0ncitCG-2jxz2hg1qj0hFc8eswWQ,1707
|
|
34
35
|
mlrun/common/schemas/client_spec.py,sha256=EFYUSstblo13-O0LTwJfnsYmxbGPAypY3idy8SHpq1c,2858
|
|
35
36
|
mlrun/common/schemas/clusterization_spec.py,sha256=aeaFJZms7r7h2HDv6ML_GDAT6gboW-PxBbc3GKPalGk,888
|
|
@@ -81,16 +82,16 @@ mlrun/datastore/sources.py,sha256=6rK3pmpQ0Mzk1p3yEvMSqiaJOpjXGsMpXOcDYlcHaP8,40
|
|
|
81
82
|
mlrun/datastore/spark_udf.py,sha256=NnnB3DZxZb-rqpRy7b-NC7QWXuuqFn3XkBDc86tU4mQ,1498
|
|
82
83
|
mlrun/datastore/spark_utils.py,sha256=50rllp6xXpXY__1LbU7aTXUU5ca8dKAfoskPre3npZo,1611
|
|
83
84
|
mlrun/datastore/store_resources.py,sha256=dfMdFy2urilECtlwLJr5CSG12MA645b-NPYDnbr5s1A,6839
|
|
84
|
-
mlrun/datastore/targets.py,sha256=
|
|
85
|
+
mlrun/datastore/targets.py,sha256=YjjvXnaEEj0ojxiOxoRSuIrbzAvuRSpFxX-9_zJFaZ0,70714
|
|
85
86
|
mlrun/datastore/utils.py,sha256=YKK9q1C0LmveQFnbh1Dkb8LwA4WbOYFTsNxziC8d0E4,5227
|
|
86
87
|
mlrun/datastore/v3io.py,sha256=oCAMpST6sKnjm5CaNsTrcwqk3bvUFzuKBvNFmUJpPfw,9252
|
|
87
88
|
mlrun/datastore/wasbfs/__init__.py,sha256=s5Ul-0kAhYqFjKDR2X0O2vDGDbLQQduElb32Ev56Te4,1343
|
|
88
89
|
mlrun/datastore/wasbfs/fs.py,sha256=MnSj7Q4OKA2L55ihCmUnj2t3GA3B77oLMdAw-yxvN9w,6151
|
|
89
90
|
mlrun/db/__init__.py,sha256=WqJ4x8lqJ7ZoKbhEyFqkYADd9P6E3citckx9e9ZLcIU,1163
|
|
90
|
-
mlrun/db/base.py,sha256=
|
|
91
|
+
mlrun/db/base.py,sha256=d6J2g2uFvJh8CcAYoFR4DxPvKsAjByKxLqGENWDoluc,18906
|
|
91
92
|
mlrun/db/factory.py,sha256=wTEKHEmdDkylM6IkTYvmEYVF8gn2HdjLoLoWICCyatI,2403
|
|
92
|
-
mlrun/db/httpdb.py,sha256=
|
|
93
|
-
mlrun/db/nopdb.py,sha256=
|
|
93
|
+
mlrun/db/httpdb.py,sha256=JtVbbetPzhpZNYb5meXMevPIRGkGu2KBbb9QTADYvLs,158600
|
|
94
|
+
mlrun/db/nopdb.py,sha256=FoEFMfnh1aSs-mcXlwA8GnnbQCIoTtFkflbFpUF5bMY,14814
|
|
94
95
|
mlrun/feature_store/__init__.py,sha256=n1F5m1svFW2chbE2dJdWzZJJiYS4E-y8PQsG9Q-F0lU,1584
|
|
95
96
|
mlrun/feature_store/api.py,sha256=bO5I_lkIPLv8j3AXYOAseSBI8RrsGwQ9m7isepuADkw,49480
|
|
96
97
|
mlrun/feature_store/common.py,sha256=DKmoRk04NCS1gv7qZuEUa2-g8WsfR6IWjYctcrqKVlg,12853
|
|
@@ -245,9 +246,9 @@ mlrun/platforms/other.py,sha256=T1BibmEBNggM62YJ6oejRmcVv_1besfH5DDHhCaDkRg,1182
|
|
|
245
246
|
mlrun/projects/__init__.py,sha256=Lv5rfxyXJrw6WGOWJKhBz66M6t3_zsNMCfUD6waPwx4,1153
|
|
246
247
|
mlrun/projects/operations.py,sha256=SiDHd7cqh9u23AVpETbkJE6WmOnB434zBrwM-StZLQY,18538
|
|
247
248
|
mlrun/projects/pipelines.py,sha256=SMXBmIeuopwPpU0o2VFvaPXgbmaj-2WfCJryN6mZvZY,40124
|
|
248
|
-
mlrun/projects/project.py,sha256=
|
|
249
|
+
mlrun/projects/project.py,sha256=7BJwLO9pdEfrP55Ppf2z3nLOQ_gPWQIhgt_pZvqKtm4,158052
|
|
249
250
|
mlrun/runtimes/__init__.py,sha256=vsoNA9ts_VPvGN9YPYKAjkxZe1RaZu22D5t-tiMyP-4,7034
|
|
250
|
-
mlrun/runtimes/base.py,sha256=
|
|
251
|
+
mlrun/runtimes/base.py,sha256=Faxa44TFCu7xA3UzYl36u1ZMpITJpTkiFJ7j-oRhJVA,36562
|
|
251
252
|
mlrun/runtimes/constants.py,sha256=oP3OxdYCpbvadJ3zP1JGkqGBKaBheNkCnJISWha9x58,9513
|
|
252
253
|
mlrun/runtimes/daskjob.py,sha256=xvN8ajs3-_voqxrfz6b3rh_idNw4ypRAkPRWGOnDMGA,19149
|
|
253
254
|
mlrun/runtimes/funcdoc.py,sha256=FHwnLfFzoD6yGlsAJXAl_3VTtudgg4fTrsw_XqLOkC0,10508
|
|
@@ -266,7 +267,8 @@ mlrun/runtimes/mpijob/__init__.py,sha256=jZf2uPBv6IB18Jj-dGSQ9NU5_xxni7XS4dnDZGw
|
|
|
266
267
|
mlrun/runtimes/mpijob/abstract.py,sha256=AqIb-nEKZaRO7x1GxJea6cXg_Tn3Dr4WiWZUz3ywCjU,9161
|
|
267
268
|
mlrun/runtimes/mpijob/v1.py,sha256=_RUlFo_3NcFf7x-QpUNVm8f7qNbRDIdUmPf_ijrv54U,3206
|
|
268
269
|
mlrun/runtimes/mpijob/v1alpha1.py,sha256=w_971wwL03hW_ksgHJXdjTdjhxCs9KJ0zNqHSQ9whIM,1034
|
|
269
|
-
mlrun/runtimes/nuclio/__init__.py,sha256=
|
|
270
|
+
mlrun/runtimes/nuclio/__init__.py,sha256=gx1kizzKv8pGT5TNloN1js1hdbxqDw3rM90sLVYVffY,794
|
|
271
|
+
mlrun/runtimes/nuclio/api_gateway.py,sha256=t4im6F8f-zPYYXrHXCFr46Rw6sGgvydIpxpgxncTUMQ,10277
|
|
270
272
|
mlrun/runtimes/nuclio/function.py,sha256=glnE8K-4rQVfQB2hCeLt8OtcpG2NFwKgEB8aRClcSJ4,47402
|
|
271
273
|
mlrun/runtimes/nuclio/nuclio.py,sha256=sLK8KdGO1LbftlL3HqPZlFOFTAAuxJACZCVl1c0Ha6E,2942
|
|
272
274
|
mlrun/runtimes/nuclio/serving.py,sha256=hzkXKCVgU6uXLYfO3H15ZWJIQiSbcKY2M_WLybHW1hM,30363
|
|
@@ -295,7 +297,7 @@ mlrun/utils/condition_evaluator.py,sha256=-nGfRmZzivn01rHTroiGY4rqEv8T1irMyhzxEe
|
|
|
295
297
|
mlrun/utils/db.py,sha256=KEa-vzicUhzIwo1wBXax2ZuXtYgf5to7wnsY3CYCiOQ,1713
|
|
296
298
|
mlrun/utils/helpers.py,sha256=guQSdMvQT8KdS2_LHXe0C9pTEC56XtsWNMliSI0i5CQ,51162
|
|
297
299
|
mlrun/utils/http.py,sha256=mQqnCsdsg9_q2WIbgoEKGQpMesslb0ErvbwYV-htarw,8700
|
|
298
|
-
mlrun/utils/logger.py,sha256=
|
|
300
|
+
mlrun/utils/logger.py,sha256=6-XMv1ucg9NqTstLpiji9qb06XHpx2LvNA8JxU1J5Tk,8133
|
|
299
301
|
mlrun/utils/regex.py,sha256=Nd7xnDHU9PEOsse6rFwLNVgU4AaYCyuwMmQ9qgx2-Vw,4581
|
|
300
302
|
mlrun/utils/retryer.py,sha256=BsST2dbGCHcY46wyGG3zWel_O9YquO0c57P3rcBxXU0,7522
|
|
301
303
|
mlrun/utils/singleton.py,sha256=p1Y-X0mPSs_At092GS-pZCA8CTR62HOqPU07_ZH6-To,869
|
|
@@ -311,11 +313,11 @@ mlrun/utils/notifications/notification/ipython.py,sha256=d47s-fW4TgqOJZOSdmzBQvd
|
|
|
311
313
|
mlrun/utils/notifications/notification/slack.py,sha256=5JysqIpUYUZKXPSeeZtbl7qb2L9dj7p2NvnEBcEsZkA,3898
|
|
312
314
|
mlrun/utils/notifications/notification/webhook.py,sha256=QHezCuN5uXkLcroAGxGrhGHaxAdUvkDLIsp27_Yrfd4,2390
|
|
313
315
|
mlrun/utils/version/__init__.py,sha256=7kkrB7hEZ3cLXoWj1kPoDwo4MaswsI2JVOBpbKgPAgc,614
|
|
314
|
-
mlrun/utils/version/version.json,sha256=
|
|
316
|
+
mlrun/utils/version/version.json,sha256=ZRswxH-AwVSByZa3TM00R47LdOv7o0_cYL3CzdifHz0,88
|
|
315
317
|
mlrun/utils/version/version.py,sha256=eEW0tqIAkU9Xifxv8Z9_qsYnNhn3YH7NRAfM-pPLt1g,1878
|
|
316
|
-
mlrun-1.7.
|
|
317
|
-
mlrun-1.7.
|
|
318
|
-
mlrun-1.7.
|
|
319
|
-
mlrun-1.7.
|
|
320
|
-
mlrun-1.7.
|
|
321
|
-
mlrun-1.7.
|
|
318
|
+
mlrun-1.7.0rc5.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
319
|
+
mlrun-1.7.0rc5.dist-info/METADATA,sha256=_bRlth3i1-0z_O8MHjRjyJPFlevk6zBa_kGp53B3mOE,18263
|
|
320
|
+
mlrun-1.7.0rc5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
321
|
+
mlrun-1.7.0rc5.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
|
|
322
|
+
mlrun-1.7.0rc5.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
|
|
323
|
+
mlrun-1.7.0rc5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|