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.
Files changed (58) hide show
  1. mlrun/api/api/endpoints/datastore_profile.py +35 -13
  2. mlrun/api/api/endpoints/files.py +1 -1
  3. mlrun/api/api/endpoints/frontend_spec.py +1 -10
  4. mlrun/api/api/endpoints/functions.py +28 -18
  5. mlrun/api/api/endpoints/hub.py +2 -6
  6. mlrun/api/api/endpoints/pipelines.py +5 -1
  7. mlrun/api/api/endpoints/projects.py +1 -0
  8. mlrun/api/api/endpoints/workflows.py +1 -0
  9. mlrun/api/api/utils.py +18 -0
  10. mlrun/api/crud/client_spec.py +3 -0
  11. mlrun/api/crud/datastore_profiles.py +2 -2
  12. mlrun/api/crud/hub.py +158 -142
  13. mlrun/api/crud/model_monitoring/deployment.py +3 -0
  14. mlrun/api/crud/model_monitoring/model_endpoints.py +1 -1
  15. mlrun/api/crud/pipelines.py +10 -4
  16. mlrun/api/crud/workflows.py +11 -4
  17. mlrun/api/db/session.py +7 -2
  18. mlrun/api/db/sqldb/db.py +19 -21
  19. mlrun/api/db/sqldb/models/models_mysql.py +10 -1
  20. mlrun/api/db/sqldb/models/models_sqlite.py +11 -1
  21. mlrun/api/initial_data.py +3 -5
  22. mlrun/api/launcher.py +2 -1
  23. mlrun/api/migrations_mysql/versions/026c947c4487_altering_table_datastore_profiles_2.py +46 -0
  24. mlrun/api/migrations_sqlite/versions/026c947c4487_altering_table_datastore_profiles_2.py +46 -0
  25. mlrun/api/rundb/sqldb.py +113 -61
  26. mlrun/api/utils/db/sqlite_migration.py +1 -0
  27. mlrun/common/model_monitoring/helpers.py +3 -1
  28. mlrun/common/schemas/client_spec.py +1 -0
  29. mlrun/common/schemas/datastore_profile.py +1 -1
  30. mlrun/common/schemas/frontend_spec.py +1 -1
  31. mlrun/config.py +3 -2
  32. mlrun/datastore/datastore_profile.py +33 -21
  33. mlrun/datastore/dbfs_store.py +9 -8
  34. mlrun/datastore/redis.py +6 -0
  35. mlrun/datastore/targets.py +12 -1
  36. mlrun/db/base.py +1 -1
  37. mlrun/db/factory.py +3 -0
  38. mlrun/db/httpdb.py +14 -13
  39. mlrun/db/nopdb.py +1 -1
  40. mlrun/feature_store/api.py +4 -1
  41. mlrun/feature_store/feature_set.py +3 -1
  42. mlrun/feature_store/ingestion.py +1 -0
  43. mlrun/kfpops.py +8 -2
  44. mlrun/launcher/base.py +1 -1
  45. mlrun/model.py +7 -5
  46. mlrun/projects/pipelines.py +7 -6
  47. mlrun/projects/project.py +2 -2
  48. mlrun/run.py +1 -1
  49. mlrun/runtimes/__init__.py +1 -0
  50. mlrun/utils/helpers.py +1 -1
  51. mlrun/utils/notifications/notification/webhook.py +9 -1
  52. mlrun/utils/version/version.json +2 -2
  53. {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/METADATA +6 -5
  54. {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/RECORD +58 -56
  55. {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/LICENSE +0 -0
  56. {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/WHEEL +0 -0
  57. {mlrun-1.5.0rc4.dist-info → mlrun-1.5.0rc6.dist-info}/entry_points.txt +0 -0
  58. {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}/datastore_profiles",
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().query_global_resource_permissions(
50
+ await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
49
51
  mlrun.common.schemas.AuthorizationResourceTypes.datastore_profile,
50
- mlrun.common.schemas.AuthorizationAction.create,
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 = project_name
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}/datastore_profiles",
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().query_global_resource_permissions(
86
- mlrun.common.schemas.AuthorizationResourceTypes.datastore_profile,
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
- return await run_in_threadpool(
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}/datastore_profiles/{profile}",
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().query_global_resource_permissions(
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}/datastore_profiles/{profile}",
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().query_global_resource_permissions(
164
+ await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
145
165
  mlrun.common.schemas.AuthorizationResourceTypes.datastore_profile,
146
- mlrun.common.schemas.AuthorizationAction.read,
166
+ project_name,
167
+ profile,
168
+ mlrun.common.schemas.AuthorizationAction.delete,
147
169
  auth_info,
148
170
  )
149
171
  return await run_in_threadpool(
@@ -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 = 0,
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
- function_deployment_mlrun_command=_resolve_function_deployment_mlrun_command(),
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(f"build_function:\n{data}")
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
- mlrun.api.api.utils.apply_enrichment_and_validation_on_function(
841
- function,
842
- auth_info,
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
- mlrun.api.crud.Functions().start_function(
846
- function, client_version, client_python_version
847
- )
848
- logger.info("Fn:\n %s", function.to_yaml())
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
- except mlrun.errors.MLRunBadRequestError:
851
- raise
858
+ except mlrun.errors.MLRunBadRequestError:
859
+ raise
852
860
 
853
- except Exception as err:
854
- logger.error(traceback.format_exc())
855
- log_and_raise(
856
- HTTPStatus.BAD_REQUEST.value,
857
- reason=f"Runtime error: {err_to_str(err)}",
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):
@@ -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().filter_hub_sources,
90
- hub_sources,
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
@@ -388,6 +388,7 @@ async def load_project(
388
388
  mlrun.api.crud.WorkflowRunners().create_runner,
389
389
  run_name=f"load-{name}",
390
390
  project=name,
391
+ db_session=db_session,
391
392
  auth_info=auth_info,
392
393
  image=mlrun.mlconf.default_base_image,
393
394
  )
@@ -141,6 +141,7 @@ async def submit_workflow(
141
141
  workflow_spec.name
142
142
  ),
143
143
  project=project.metadata.name,
144
+ db_session=db_session,
144
145
  auth_info=auth_info,
145
146
  image=workflow_spec.image
146
147
  or project.spec.default_image
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:
@@ -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, hub source credentials cannot be stored securely"
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, hub source credentials cannot be stored securely"
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)