mlrun 1.5.0rc4__py3-none-any.whl → 1.5.0rc6__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.
- mlrun/api/api/endpoints/datastore_profile.py +35 -13
- mlrun/api/api/endpoints/files.py +1 -1
- mlrun/api/api/endpoints/frontend_spec.py +1 -10
- mlrun/api/api/endpoints/functions.py +28 -18
- mlrun/api/api/endpoints/hub.py +2 -6
- mlrun/api/api/endpoints/pipelines.py +5 -1
- mlrun/api/api/endpoints/projects.py +1 -0
- mlrun/api/api/endpoints/workflows.py +1 -0
- mlrun/api/api/utils.py +18 -0
- mlrun/api/crud/client_spec.py +3 -0
- mlrun/api/crud/datastore_profiles.py +2 -2
- mlrun/api/crud/hub.py +158 -142
- mlrun/api/crud/model_monitoring/deployment.py +3 -0
- mlrun/api/crud/model_monitoring/model_endpoints.py +1 -1
- mlrun/api/crud/pipelines.py +10 -4
- mlrun/api/crud/workflows.py +11 -4
- mlrun/api/db/session.py +7 -2
- mlrun/api/db/sqldb/db.py +19 -21
- mlrun/api/db/sqldb/models/models_mysql.py +10 -1
- mlrun/api/db/sqldb/models/models_sqlite.py +11 -1
- mlrun/api/initial_data.py +3 -5
- mlrun/api/launcher.py +2 -1
- mlrun/api/migrations_mysql/versions/026c947c4487_altering_table_datastore_profiles_2.py +46 -0
- mlrun/api/migrations_sqlite/versions/026c947c4487_altering_table_datastore_profiles_2.py +46 -0
- mlrun/api/rundb/sqldb.py +113 -61
- mlrun/api/utils/db/sqlite_migration.py +1 -0
- mlrun/common/model_monitoring/helpers.py +3 -1
- mlrun/common/schemas/client_spec.py +1 -0
- mlrun/common/schemas/datastore_profile.py +1 -1
- mlrun/common/schemas/frontend_spec.py +1 -1
- mlrun/config.py +3 -2
- mlrun/datastore/datastore_profile.py +33 -21
- mlrun/datastore/dbfs_store.py +9 -8
- mlrun/datastore/redis.py +6 -0
- mlrun/datastore/targets.py +12 -1
- mlrun/db/base.py +1 -1
- mlrun/db/factory.py +3 -0
- mlrun/db/httpdb.py +14 -13
- mlrun/db/nopdb.py +1 -1
- mlrun/feature_store/api.py +4 -1
- mlrun/feature_store/feature_set.py +3 -1
- mlrun/feature_store/ingestion.py +1 -0
- mlrun/kfpops.py +8 -2
- mlrun/launcher/base.py +1 -1
- mlrun/model.py +7 -5
- mlrun/projects/pipelines.py +7 -6
- mlrun/projects/project.py +2 -2
- mlrun/run.py +1 -1
- mlrun/runtimes/__init__.py +1 -0
- mlrun/utils/helpers.py +1 -1
- mlrun/utils/notifications/notification/webhook.py +9 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/METADATA +6 -5
- {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/RECORD +58 -56
- {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/LICENSE +0 -0
- {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/WHEEL +0 -0
- {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/entry_points.txt +0 -0
- {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/top_level.txt +0 -0
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
15
|
|
|
16
|
+
from http import HTTPStatus
|
|
16
17
|
|
|
17
18
|
from fastapi import APIRouter, Depends
|
|
18
19
|
from fastapi.concurrency import run_in_threadpool
|
|
@@ -24,12 +25,13 @@ import mlrun.api.crud
|
|
|
24
25
|
import mlrun.api.utils.auth.verifier
|
|
25
26
|
import mlrun.api.utils.singletons.db
|
|
26
27
|
import mlrun.common.schemas
|
|
28
|
+
from mlrun.api.api.utils import log_and_raise
|
|
27
29
|
|
|
28
30
|
router = APIRouter()
|
|
29
31
|
|
|
30
32
|
|
|
31
33
|
@router.put(
|
|
32
|
-
path="/projects/{project_name}/
|
|
34
|
+
path="/projects/{project_name}/datastore-profiles",
|
|
33
35
|
)
|
|
34
36
|
async def store_datastore_profile(
|
|
35
37
|
project_name: str,
|
|
@@ -45,13 +47,20 @@ async def store_datastore_profile(
|
|
|
45
47
|
project_name,
|
|
46
48
|
auth_info.session,
|
|
47
49
|
)
|
|
48
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().
|
|
50
|
+
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
|
|
49
51
|
mlrun.common.schemas.AuthorizationResourceTypes.datastore_profile,
|
|
50
|
-
|
|
52
|
+
project_name,
|
|
53
|
+
info.name,
|
|
54
|
+
mlrun.common.schemas.AuthorizationAction.store,
|
|
51
55
|
auth_info,
|
|
52
56
|
)
|
|
53
57
|
# overwrite the project
|
|
54
|
-
info.project
|
|
58
|
+
if info.project != project_name:
|
|
59
|
+
log_and_raise(
|
|
60
|
+
HTTPStatus.BAD_REQUEST.value,
|
|
61
|
+
reason="The project name provided in the URI does not match the one specified in the DatastoreProfile",
|
|
62
|
+
)
|
|
63
|
+
|
|
55
64
|
await run_in_threadpool(
|
|
56
65
|
mlrun.api.utils.singletons.db.get_db().store_datastore_profile,
|
|
57
66
|
db_session,
|
|
@@ -67,7 +76,7 @@ async def store_datastore_profile(
|
|
|
67
76
|
|
|
68
77
|
|
|
69
78
|
@router.get(
|
|
70
|
-
path="/projects/{project_name}/
|
|
79
|
+
path="/projects/{project_name}/datastore-profiles",
|
|
71
80
|
)
|
|
72
81
|
async def list_datastore_profiles(
|
|
73
82
|
project_name: str,
|
|
@@ -82,20 +91,29 @@ async def list_datastore_profiles(
|
|
|
82
91
|
project_name,
|
|
83
92
|
auth_info.session,
|
|
84
93
|
)
|
|
85
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().
|
|
86
|
-
|
|
94
|
+
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_permissions(
|
|
95
|
+
project_name,
|
|
87
96
|
mlrun.common.schemas.AuthorizationAction.read,
|
|
88
97
|
auth_info,
|
|
89
98
|
)
|
|
90
|
-
|
|
99
|
+
profiles = await run_in_threadpool(
|
|
91
100
|
mlrun.api.utils.singletons.db.get_db().list_datastore_profiles,
|
|
92
101
|
db_session,
|
|
93
102
|
project_name,
|
|
94
103
|
)
|
|
104
|
+
if len(profiles) == 0:
|
|
105
|
+
return profiles
|
|
106
|
+
filtered_data = await mlrun.api.utils.auth.verifier.AuthVerifier().filter_project_resources_by_permissions(
|
|
107
|
+
mlrun.common.schemas.AuthorizationResourceTypes.datastore_profile,
|
|
108
|
+
profiles,
|
|
109
|
+
lambda profile: (project_name, profile.name),
|
|
110
|
+
auth_info,
|
|
111
|
+
)
|
|
112
|
+
return filtered_data
|
|
95
113
|
|
|
96
114
|
|
|
97
115
|
@router.get(
|
|
98
|
-
path="/projects/{project_name}/
|
|
116
|
+
path="/projects/{project_name}/datastore-profiles/{profile}",
|
|
99
117
|
)
|
|
100
118
|
async def get_datastore_profile(
|
|
101
119
|
project_name: str,
|
|
@@ -111,8 +129,10 @@ async def get_datastore_profile(
|
|
|
111
129
|
project_name,
|
|
112
130
|
auth_info.session,
|
|
113
131
|
)
|
|
114
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().
|
|
132
|
+
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
|
|
115
133
|
mlrun.common.schemas.AuthorizationResourceTypes.datastore_profile,
|
|
134
|
+
project_name,
|
|
135
|
+
profile,
|
|
116
136
|
mlrun.common.schemas.AuthorizationAction.read,
|
|
117
137
|
auth_info,
|
|
118
138
|
)
|
|
@@ -125,7 +145,7 @@ async def get_datastore_profile(
|
|
|
125
145
|
|
|
126
146
|
|
|
127
147
|
@router.delete(
|
|
128
|
-
path="/projects/{project_name}/
|
|
148
|
+
path="/projects/{project_name}/datastore-profiles/{profile}",
|
|
129
149
|
)
|
|
130
150
|
async def delete_datastore_profile(
|
|
131
151
|
project_name: str,
|
|
@@ -141,9 +161,11 @@ async def delete_datastore_profile(
|
|
|
141
161
|
project_name,
|
|
142
162
|
auth_info.session,
|
|
143
163
|
)
|
|
144
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().
|
|
164
|
+
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
|
|
145
165
|
mlrun.common.schemas.AuthorizationResourceTypes.datastore_profile,
|
|
146
|
-
|
|
166
|
+
project_name,
|
|
167
|
+
profile,
|
|
168
|
+
mlrun.common.schemas.AuthorizationAction.delete,
|
|
147
169
|
auth_info,
|
|
148
170
|
)
|
|
149
171
|
return await run_in_threadpool(
|
mlrun/api/api/endpoints/files.py
CHANGED
|
@@ -42,7 +42,7 @@ def get_files(
|
|
|
42
42
|
schema: str = "",
|
|
43
43
|
objpath: str = fastapi.Query("", alias="path"),
|
|
44
44
|
user: str = "",
|
|
45
|
-
size: int =
|
|
45
|
+
size: int = None,
|
|
46
46
|
offset: int = 0,
|
|
47
47
|
auth_info: mlrun.common.schemas.AuthInfo = fastapi.Depends(
|
|
48
48
|
mlrun.api.api.deps.authenticate_request
|
|
@@ -73,7 +73,7 @@ def get_frontend_spec(
|
|
|
73
73
|
function_deployment_target_image_template=function_deployment_target_image_template,
|
|
74
74
|
function_deployment_target_image_name_prefix_template=function_target_image_name_prefix_template,
|
|
75
75
|
function_deployment_target_image_registries_to_enforce_prefix=registries_to_enforce_prefix,
|
|
76
|
-
|
|
76
|
+
function_deployment_mlrun_requirement=mlrun.api.utils.builder.resolve_mlrun_install_command_version(),
|
|
77
77
|
auto_mount_type=config.storage.auto_mount_type,
|
|
78
78
|
auto_mount_params=config.get_storage_auto_mount_params(),
|
|
79
79
|
default_artifact_path=config.artifact_path,
|
|
@@ -87,15 +87,6 @@ def get_frontend_spec(
|
|
|
87
87
|
)
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
def _resolve_function_deployment_mlrun_command():
|
|
91
|
-
# TODO: When UI adds a requirements section, mlrun should be specified there instead of the commands section i.e.
|
|
92
|
-
# frontend spec will contain only the mlrun_version_specifier instead of the full command
|
|
93
|
-
mlrun_version_specifier = (
|
|
94
|
-
mlrun.api.utils.builder.resolve_mlrun_install_command_version()
|
|
95
|
-
)
|
|
96
|
-
return f'python -m pip install "{mlrun_version_specifier}"'
|
|
97
|
-
|
|
98
|
-
|
|
99
90
|
def _resolve_jobs_dashboard_url(session: str) -> typing.Optional[str]:
|
|
100
91
|
iguazio_client = mlrun.api.utils.clients.iguazio.Client()
|
|
101
92
|
grafana_service_url = iguazio_client.try_get_grafana_service_url(session)
|
|
@@ -47,7 +47,7 @@ import mlrun.common.model_monitoring
|
|
|
47
47
|
import mlrun.common.model_monitoring.helpers
|
|
48
48
|
import mlrun.common.schemas
|
|
49
49
|
from mlrun.api.api import deps
|
|
50
|
-
from mlrun.api.api.utils import log_and_raise, log_path
|
|
50
|
+
from mlrun.api.api.utils import get_run_db_instance, log_and_raise, log_path
|
|
51
51
|
from mlrun.api.crud.secrets import Secrets, SecretsClientType
|
|
52
52
|
from mlrun.api.utils.builder import build_runtime
|
|
53
53
|
from mlrun.api.utils.singletons.scheduler import get_scheduler
|
|
@@ -267,7 +267,7 @@ async def build_function(
|
|
|
267
267
|
except ValueError:
|
|
268
268
|
log_and_raise(HTTPStatus.BAD_REQUEST.value, reason="bad JSON body")
|
|
269
269
|
|
|
270
|
-
logger.info(
|
|
270
|
+
logger.info("Building function", data=data)
|
|
271
271
|
function = data.get("function")
|
|
272
272
|
project = function.get("metadata", {}).get("project", mlrun.mlconf.default_project)
|
|
273
273
|
function_name = function.get("metadata", {}).get("name")
|
|
@@ -706,6 +706,10 @@ def _build_function(
|
|
|
706
706
|
reason=f"runtime error: {err_to_str(err)}",
|
|
707
707
|
)
|
|
708
708
|
try:
|
|
709
|
+
# connect to run db
|
|
710
|
+
run_db = get_run_db_instance(db_session)
|
|
711
|
+
fn.set_db_connection(run_db)
|
|
712
|
+
|
|
709
713
|
is_nuclio_runtime = fn.kind in RuntimeKinds.nuclio_runtimes()
|
|
710
714
|
|
|
711
715
|
# Enrich runtime with project defaults
|
|
@@ -836,26 +840,32 @@ def _start_function(
|
|
|
836
840
|
client_version: str = None,
|
|
837
841
|
client_python_version: str = None,
|
|
838
842
|
):
|
|
843
|
+
db_session = mlrun.api.db.session.create_session()
|
|
839
844
|
try:
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
845
|
+
try:
|
|
846
|
+
run_db = get_run_db_instance(db_session)
|
|
847
|
+
function.set_db_connection(run_db)
|
|
848
|
+
mlrun.api.api.utils.apply_enrichment_and_validation_on_function(
|
|
849
|
+
function,
|
|
850
|
+
auth_info,
|
|
851
|
+
)
|
|
844
852
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
853
|
+
mlrun.api.crud.Functions().start_function(
|
|
854
|
+
function, client_version, client_python_version
|
|
855
|
+
)
|
|
856
|
+
logger.info("Fn:\n %s", function.to_yaml())
|
|
849
857
|
|
|
850
|
-
|
|
851
|
-
|
|
858
|
+
except mlrun.errors.MLRunBadRequestError:
|
|
859
|
+
raise
|
|
852
860
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
861
|
+
except Exception as err:
|
|
862
|
+
logger.error(traceback.format_exc())
|
|
863
|
+
log_and_raise(
|
|
864
|
+
HTTPStatus.BAD_REQUEST.value,
|
|
865
|
+
reason=f"Runtime error: {err_to_str(err)}",
|
|
866
|
+
)
|
|
867
|
+
finally:
|
|
868
|
+
mlrun.api.db.session.close_session(db_session)
|
|
859
869
|
|
|
860
870
|
|
|
861
871
|
async def _get_function_status(data, auth_info: mlrun.common.schemas.AuthInfo):
|
mlrun/api/api/endpoints/hub.py
CHANGED
|
@@ -81,13 +81,9 @@ async def list_sources(
|
|
|
81
81
|
auth_info,
|
|
82
82
|
)
|
|
83
83
|
|
|
84
|
-
hub_sources = await run_in_threadpool(
|
|
85
|
-
mlrun.api.utils.singletons.db.get_db().list_hub_sources, db_session
|
|
86
|
-
)
|
|
87
|
-
|
|
88
84
|
return await run_in_threadpool(
|
|
89
|
-
mlrun.api.crud.Hub().
|
|
90
|
-
|
|
85
|
+
mlrun.api.crud.Hub().list_hub_sources,
|
|
86
|
+
db_session,
|
|
91
87
|
item_name,
|
|
92
88
|
tag,
|
|
93
89
|
version,
|
|
@@ -129,9 +129,11 @@ async def get_pipeline(
|
|
|
129
129
|
auth_info: mlrun.common.schemas.AuthInfo = Depends(
|
|
130
130
|
mlrun.api.api.deps.authenticate_request
|
|
131
131
|
),
|
|
132
|
+
db_session: Session = Depends(deps.get_db_session),
|
|
132
133
|
):
|
|
133
134
|
pipeline = await run_in_threadpool(
|
|
134
135
|
mlrun.api.crud.Pipelines().get_pipeline,
|
|
136
|
+
db_session,
|
|
135
137
|
run_id,
|
|
136
138
|
project,
|
|
137
139
|
namespace,
|
|
@@ -143,7 +145,7 @@ async def get_pipeline(
|
|
|
143
145
|
# legacy flow in which we first get the pipeline, resolve the project out of it, and only then query permissions
|
|
144
146
|
# we don't use the return value from this function since the user may have asked for a different format than
|
|
145
147
|
# summary which is the one used inside
|
|
146
|
-
await _get_pipeline_without_project(auth_info, run_id, namespace)
|
|
148
|
+
await _get_pipeline_without_project(db_session, auth_info, run_id, namespace)
|
|
147
149
|
else:
|
|
148
150
|
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
|
|
149
151
|
mlrun.common.schemas.AuthorizationResourceTypes.pipeline,
|
|
@@ -156,6 +158,7 @@ async def get_pipeline(
|
|
|
156
158
|
|
|
157
159
|
|
|
158
160
|
async def _get_pipeline_without_project(
|
|
161
|
+
db_session: Session,
|
|
159
162
|
auth_info: mlrun.common.schemas.AuthInfo,
|
|
160
163
|
run_id: str,
|
|
161
164
|
namespace: str,
|
|
@@ -167,6 +170,7 @@ async def _get_pipeline_without_project(
|
|
|
167
170
|
"""
|
|
168
171
|
run = await run_in_threadpool(
|
|
169
172
|
mlrun.api.crud.Pipelines().get_pipeline,
|
|
173
|
+
db_session,
|
|
170
174
|
run_id,
|
|
171
175
|
namespace=namespace,
|
|
172
176
|
# minimal format that includes the project
|
mlrun/api/api/utils.py
CHANGED
|
@@ -36,6 +36,8 @@ import mlrun.common.schemas
|
|
|
36
36
|
import mlrun.errors
|
|
37
37
|
import mlrun.runtimes.pod
|
|
38
38
|
import mlrun.utils.helpers
|
|
39
|
+
from mlrun.api.db.sqldb.db import SQLDB
|
|
40
|
+
from mlrun.api.rundb.sqldb import SQLRunDB
|
|
39
41
|
from mlrun.api.utils.singletons.db import get_db
|
|
40
42
|
from mlrun.api.utils.singletons.logs_dir import get_logs_dir
|
|
41
43
|
from mlrun.api.utils.singletons.scheduler import get_scheduler
|
|
@@ -128,6 +130,20 @@ def get_secrets(
|
|
|
128
130
|
}
|
|
129
131
|
|
|
130
132
|
|
|
133
|
+
def get_run_db_instance(
|
|
134
|
+
db_session: Session,
|
|
135
|
+
):
|
|
136
|
+
# TODO: getting the run db should be done seamlessly by the run db factory and not require this logic to
|
|
137
|
+
# inject the session
|
|
138
|
+
db = get_db()
|
|
139
|
+
if isinstance(db, SQLDB):
|
|
140
|
+
run_db = SQLRunDB(db.dsn, db_session)
|
|
141
|
+
else:
|
|
142
|
+
run_db = db.db
|
|
143
|
+
run_db.connect()
|
|
144
|
+
return run_db
|
|
145
|
+
|
|
146
|
+
|
|
131
147
|
def parse_submit_run_body(data):
|
|
132
148
|
task = data.get("task")
|
|
133
149
|
function_dict = data.get("function")
|
|
@@ -867,6 +883,8 @@ def submit_run_sync(
|
|
|
867
883
|
try:
|
|
868
884
|
fn, task = _generate_function_and_task_from_submit_run_body(db_session, data)
|
|
869
885
|
|
|
886
|
+
run_db = get_run_db_instance(db_session)
|
|
887
|
+
fn.set_db_connection(run_db)
|
|
870
888
|
logger.info("Submitting run", function=fn.to_dict(), task=task)
|
|
871
889
|
schedule = data.get("schedule")
|
|
872
890
|
if schedule:
|
mlrun/api/crud/client_spec.py
CHANGED
|
@@ -104,6 +104,9 @@ class ClientSpec(
|
|
|
104
104
|
model_endpoint_monitoring_store_type=self._get_config_value_if_not_default(
|
|
105
105
|
"model_endpoint_monitoring.store_type"
|
|
106
106
|
),
|
|
107
|
+
model_endpoint_monitoring_endpoint_store_connection=self._get_config_value_if_not_default(
|
|
108
|
+
"model_endpoint_monitoring.endpoint_store_connection"
|
|
109
|
+
),
|
|
107
110
|
packagers=self._get_config_value_if_not_default("packagers"),
|
|
108
111
|
)
|
|
109
112
|
|
|
@@ -37,7 +37,7 @@ class DatastoreProfiles(
|
|
|
37
37
|
def _store_secret(self, project, profile_name, profile_secret_json):
|
|
38
38
|
if not self._in_k8s():
|
|
39
39
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
40
|
-
"MLRun is not configured with k8s,
|
|
40
|
+
"MLRun is not configured with k8s, datastore profile credentials cannot be stored securely"
|
|
41
41
|
)
|
|
42
42
|
|
|
43
43
|
adjusted_secret = {
|
|
@@ -56,7 +56,7 @@ class DatastoreProfiles(
|
|
|
56
56
|
def _delete_secret(self, project, profile_name):
|
|
57
57
|
if not self._in_k8s():
|
|
58
58
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
59
|
-
"MLRun is not configured with k8s,
|
|
59
|
+
"MLRun is not configured with k8s, datastore profile credentials cannot be deleted"
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
adjusted_secret = dsp.generate_secret_key(profile_name, project)
|