mlrun 1.3.3rc1__py3-none-any.whl → 1.4.0__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.

Files changed (444) hide show
  1. mlrun/__init__.py +3 -3
  2. mlrun/__main__.py +79 -37
  3. mlrun/api/__init__.py +1 -1
  4. mlrun/api/api/__init__.py +1 -1
  5. mlrun/api/api/api.py +4 -4
  6. mlrun/api/api/deps.py +10 -21
  7. mlrun/api/api/endpoints/__init__.py +1 -1
  8. mlrun/api/api/endpoints/artifacts.py +64 -36
  9. mlrun/api/api/endpoints/auth.py +4 -4
  10. mlrun/api/api/endpoints/background_tasks.py +11 -11
  11. mlrun/api/api/endpoints/client_spec.py +5 -5
  12. mlrun/api/api/endpoints/clusterization_spec.py +6 -4
  13. mlrun/api/api/endpoints/feature_store.py +124 -115
  14. mlrun/api/api/endpoints/files.py +22 -14
  15. mlrun/api/api/endpoints/frontend_spec.py +28 -21
  16. mlrun/api/api/endpoints/functions.py +142 -87
  17. mlrun/api/api/endpoints/grafana_proxy.py +89 -442
  18. mlrun/api/api/endpoints/healthz.py +20 -7
  19. mlrun/api/api/endpoints/hub.py +320 -0
  20. mlrun/api/api/endpoints/internal/__init__.py +1 -1
  21. mlrun/api/api/endpoints/internal/config.py +1 -1
  22. mlrun/api/api/endpoints/internal/memory_reports.py +9 -9
  23. mlrun/api/api/endpoints/logs.py +11 -11
  24. mlrun/api/api/endpoints/model_endpoints.py +74 -70
  25. mlrun/api/api/endpoints/operations.py +13 -9
  26. mlrun/api/api/endpoints/pipelines.py +93 -88
  27. mlrun/api/api/endpoints/projects.py +35 -35
  28. mlrun/api/api/endpoints/runs.py +69 -27
  29. mlrun/api/api/endpoints/runtime_resources.py +28 -28
  30. mlrun/api/api/endpoints/schedules.py +98 -41
  31. mlrun/api/api/endpoints/secrets.py +37 -32
  32. mlrun/api/api/endpoints/submit.py +12 -12
  33. mlrun/api/api/endpoints/tags.py +20 -22
  34. mlrun/api/api/utils.py +251 -42
  35. mlrun/api/constants.py +1 -1
  36. mlrun/api/crud/__init__.py +18 -15
  37. mlrun/api/crud/artifacts.py +10 -10
  38. mlrun/api/crud/client_spec.py +4 -4
  39. mlrun/api/crud/clusterization_spec.py +3 -3
  40. mlrun/api/crud/feature_store.py +54 -46
  41. mlrun/api/crud/functions.py +3 -3
  42. mlrun/api/crud/hub.py +312 -0
  43. mlrun/api/crud/logs.py +11 -9
  44. mlrun/api/crud/model_monitoring/__init__.py +3 -3
  45. mlrun/api/crud/model_monitoring/grafana.py +435 -0
  46. mlrun/api/crud/model_monitoring/model_endpoints.py +352 -129
  47. mlrun/api/crud/notifications.py +149 -0
  48. mlrun/api/crud/pipelines.py +67 -52
  49. mlrun/api/crud/projects.py +51 -23
  50. mlrun/api/crud/runs.py +7 -5
  51. mlrun/api/crud/runtime_resources.py +13 -13
  52. mlrun/api/{db/filedb → crud/runtimes}/__init__.py +1 -1
  53. mlrun/api/crud/runtimes/nuclio/__init__.py +14 -0
  54. mlrun/api/crud/runtimes/nuclio/function.py +505 -0
  55. mlrun/api/crud/runtimes/nuclio/helpers.py +310 -0
  56. mlrun/api/crud/secrets.py +88 -46
  57. mlrun/api/crud/tags.py +5 -5
  58. mlrun/api/db/__init__.py +1 -1
  59. mlrun/api/db/base.py +102 -54
  60. mlrun/api/db/init_db.py +2 -3
  61. mlrun/api/db/session.py +4 -12
  62. mlrun/api/db/sqldb/__init__.py +1 -1
  63. mlrun/api/db/sqldb/db.py +439 -196
  64. mlrun/api/db/sqldb/helpers.py +1 -1
  65. mlrun/api/db/sqldb/models/__init__.py +3 -3
  66. mlrun/api/db/sqldb/models/models_mysql.py +82 -64
  67. mlrun/api/db/sqldb/models/models_sqlite.py +76 -64
  68. mlrun/api/db/sqldb/session.py +27 -20
  69. mlrun/api/initial_data.py +82 -24
  70. mlrun/api/launcher.py +196 -0
  71. mlrun/api/main.py +91 -22
  72. mlrun/api/middlewares.py +6 -5
  73. mlrun/api/migrations_mysql/env.py +1 -1
  74. mlrun/api/migrations_mysql/versions/28383af526f3_market_place_to_hub.py +40 -0
  75. mlrun/api/migrations_mysql/versions/32bae1b0e29c_increase_timestamp_fields_precision.py +1 -1
  76. mlrun/api/migrations_mysql/versions/4903aef6a91d_tag_foreign_key_and_cascades.py +1 -1
  77. mlrun/api/migrations_mysql/versions/5f1351c88a19_adding_background_tasks_table.py +1 -1
  78. mlrun/api/migrations_mysql/versions/88e656800d6a_add_requested_logs_column_and_index_to_.py +1 -1
  79. mlrun/api/migrations_mysql/versions/9d16de5f03a7_adding_data_versions_table.py +1 -1
  80. mlrun/api/migrations_mysql/versions/b86f5b53f3d7_adding_name_and_updated_to_runs_table.py +1 -1
  81. mlrun/api/migrations_mysql/versions/c4af40b0bf61_init.py +1 -1
  82. mlrun/api/migrations_mysql/versions/c905d15bd91d_notifications.py +72 -0
  83. mlrun/api/migrations_mysql/versions/ee041e8fdaa0_adding_next_run_time_column_to_schedule_.py +1 -1
  84. mlrun/api/migrations_sqlite/env.py +1 -1
  85. mlrun/api/migrations_sqlite/versions/11f8dd2dc9fe_init.py +1 -1
  86. mlrun/api/migrations_sqlite/versions/1c954f8cb32d_schedule_last_run_uri.py +1 -1
  87. mlrun/api/migrations_sqlite/versions/2b6d23c715aa_adding_feature_sets.py +1 -1
  88. mlrun/api/migrations_sqlite/versions/4acd9430b093_market_place_to_hub.py +77 -0
  89. mlrun/api/migrations_sqlite/versions/6401142f2d7c_adding_next_run_time_column_to_schedule_.py +1 -1
  90. mlrun/api/migrations_sqlite/versions/64d90a1a69bc_adding_background_tasks_table.py +1 -1
  91. mlrun/api/migrations_sqlite/versions/803438ecd005_add_requested_logs_column_to_runs.py +1 -1
  92. mlrun/api/migrations_sqlite/versions/863114f0c659_refactoring_feature_set.py +1 -1
  93. mlrun/api/migrations_sqlite/versions/959ae00528ad_notifications.py +63 -0
  94. mlrun/api/migrations_sqlite/versions/accf9fc83d38_adding_data_versions_table.py +1 -1
  95. mlrun/api/migrations_sqlite/versions/b68e8e897a28_schedule_labels.py +1 -1
  96. mlrun/api/migrations_sqlite/versions/bcd0c1f9720c_adding_project_labels.py +1 -1
  97. mlrun/api/migrations_sqlite/versions/cf21882f938e_schedule_id.py +1 -1
  98. mlrun/api/migrations_sqlite/versions/d781f58f607f_tag_object_name_string.py +1 -1
  99. mlrun/api/migrations_sqlite/versions/deac06871ace_adding_marketplace_sources_table.py +1 -1
  100. mlrun/api/migrations_sqlite/versions/e1dd5983c06b_schedule_concurrency_limit.py +1 -1
  101. mlrun/api/migrations_sqlite/versions/e5594ed3ab53_adding_name_and_updated_to_runs_table.py +1 -1
  102. mlrun/api/migrations_sqlite/versions/f4249b4ba6fa_adding_feature_vectors.py +1 -1
  103. mlrun/api/migrations_sqlite/versions/f7b5a1a03629_adding_feature_labels.py +1 -1
  104. mlrun/api/schemas/__init__.py +216 -138
  105. mlrun/api/utils/__init__.py +1 -1
  106. mlrun/api/utils/asyncio.py +1 -1
  107. mlrun/api/utils/auth/__init__.py +1 -1
  108. mlrun/api/utils/auth/providers/__init__.py +1 -1
  109. mlrun/api/utils/auth/providers/base.py +7 -7
  110. mlrun/api/utils/auth/providers/nop.py +6 -7
  111. mlrun/api/utils/auth/providers/opa.py +17 -17
  112. mlrun/api/utils/auth/verifier.py +36 -34
  113. mlrun/api/utils/background_tasks.py +24 -24
  114. mlrun/{builder.py → api/utils/builder.py} +216 -123
  115. mlrun/api/utils/clients/__init__.py +1 -1
  116. mlrun/api/utils/clients/chief.py +19 -4
  117. mlrun/api/utils/clients/iguazio.py +106 -60
  118. mlrun/api/utils/clients/log_collector.py +1 -1
  119. mlrun/api/utils/clients/nuclio.py +23 -23
  120. mlrun/api/utils/clients/protocols/grpc.py +2 -2
  121. mlrun/api/utils/db/__init__.py +1 -1
  122. mlrun/api/utils/db/alembic.py +1 -1
  123. mlrun/api/utils/db/backup.py +1 -1
  124. mlrun/api/utils/db/mysql.py +24 -25
  125. mlrun/api/utils/db/sql_collation.py +1 -1
  126. mlrun/api/utils/db/sqlite_migration.py +2 -2
  127. mlrun/api/utils/events/__init__.py +14 -0
  128. mlrun/api/utils/events/base.py +57 -0
  129. mlrun/api/utils/events/events_factory.py +41 -0
  130. mlrun/api/utils/events/iguazio.py +217 -0
  131. mlrun/api/utils/events/nop.py +55 -0
  132. mlrun/api/utils/helpers.py +16 -13
  133. mlrun/api/utils/memory_reports.py +1 -1
  134. mlrun/api/utils/periodic.py +6 -3
  135. mlrun/api/utils/projects/__init__.py +1 -1
  136. mlrun/api/utils/projects/follower.py +33 -33
  137. mlrun/api/utils/projects/leader.py +36 -34
  138. mlrun/api/utils/projects/member.py +27 -27
  139. mlrun/api/utils/projects/remotes/__init__.py +1 -1
  140. mlrun/api/utils/projects/remotes/follower.py +13 -13
  141. mlrun/api/utils/projects/remotes/leader.py +10 -10
  142. mlrun/api/utils/projects/remotes/nop_follower.py +27 -21
  143. mlrun/api/utils/projects/remotes/nop_leader.py +17 -16
  144. mlrun/api/utils/scheduler.py +140 -51
  145. mlrun/api/utils/singletons/__init__.py +1 -1
  146. mlrun/api/utils/singletons/db.py +9 -15
  147. mlrun/api/utils/singletons/k8s.py +677 -5
  148. mlrun/api/utils/singletons/logs_dir.py +1 -1
  149. mlrun/api/utils/singletons/project_member.py +1 -1
  150. mlrun/api/utils/singletons/scheduler.py +1 -1
  151. mlrun/artifacts/__init__.py +2 -2
  152. mlrun/artifacts/base.py +8 -2
  153. mlrun/artifacts/dataset.py +5 -3
  154. mlrun/artifacts/manager.py +7 -1
  155. mlrun/artifacts/model.py +15 -4
  156. mlrun/artifacts/plots.py +1 -1
  157. mlrun/common/__init__.py +1 -1
  158. mlrun/common/constants.py +15 -0
  159. mlrun/common/model_monitoring.py +209 -0
  160. mlrun/common/schemas/__init__.py +167 -0
  161. mlrun/{api → common}/schemas/artifact.py +13 -14
  162. mlrun/{api → common}/schemas/auth.py +10 -8
  163. mlrun/{api → common}/schemas/background_task.py +3 -3
  164. mlrun/{api → common}/schemas/client_spec.py +1 -1
  165. mlrun/{api → common}/schemas/clusterization_spec.py +3 -3
  166. mlrun/{api → common}/schemas/constants.py +21 -8
  167. mlrun/common/schemas/events.py +36 -0
  168. mlrun/{api → common}/schemas/feature_store.py +2 -1
  169. mlrun/{api → common}/schemas/frontend_spec.py +7 -6
  170. mlrun/{api → common}/schemas/function.py +5 -5
  171. mlrun/{api → common}/schemas/http.py +3 -3
  172. mlrun/common/schemas/hub.py +134 -0
  173. mlrun/{api → common}/schemas/k8s.py +3 -3
  174. mlrun/{api → common}/schemas/memory_reports.py +1 -1
  175. mlrun/common/schemas/model_endpoints.py +342 -0
  176. mlrun/common/schemas/notification.py +57 -0
  177. mlrun/{api → common}/schemas/object.py +6 -6
  178. mlrun/{api → common}/schemas/pipeline.py +3 -3
  179. mlrun/{api → common}/schemas/project.py +6 -5
  180. mlrun/common/schemas/regex.py +24 -0
  181. mlrun/common/schemas/runs.py +30 -0
  182. mlrun/{api → common}/schemas/runtime_resource.py +3 -3
  183. mlrun/{api → common}/schemas/schedule.py +19 -7
  184. mlrun/{api → common}/schemas/secret.py +3 -3
  185. mlrun/{api → common}/schemas/tag.py +2 -2
  186. mlrun/common/types.py +25 -0
  187. mlrun/config.py +152 -20
  188. mlrun/data_types/__init__.py +7 -2
  189. mlrun/data_types/data_types.py +4 -2
  190. mlrun/data_types/infer.py +1 -1
  191. mlrun/data_types/spark.py +10 -3
  192. mlrun/datastore/__init__.py +10 -3
  193. mlrun/datastore/azure_blob.py +1 -1
  194. mlrun/datastore/base.py +185 -53
  195. mlrun/datastore/datastore.py +1 -1
  196. mlrun/datastore/filestore.py +1 -1
  197. mlrun/datastore/google_cloud_storage.py +1 -1
  198. mlrun/datastore/inmem.py +4 -1
  199. mlrun/datastore/redis.py +1 -1
  200. mlrun/datastore/s3.py +1 -1
  201. mlrun/datastore/sources.py +192 -70
  202. mlrun/datastore/spark_udf.py +44 -0
  203. mlrun/datastore/store_resources.py +4 -4
  204. mlrun/datastore/targets.py +115 -45
  205. mlrun/datastore/utils.py +127 -5
  206. mlrun/datastore/v3io.py +1 -1
  207. mlrun/datastore/wasbfs/__init__.py +1 -1
  208. mlrun/datastore/wasbfs/fs.py +1 -1
  209. mlrun/db/__init__.py +7 -5
  210. mlrun/db/base.py +112 -68
  211. mlrun/db/httpdb.py +445 -277
  212. mlrun/db/nopdb.py +491 -0
  213. mlrun/db/sqldb.py +112 -65
  214. mlrun/errors.py +6 -1
  215. mlrun/execution.py +44 -22
  216. mlrun/feature_store/__init__.py +1 -1
  217. mlrun/feature_store/api.py +143 -95
  218. mlrun/feature_store/common.py +16 -20
  219. mlrun/feature_store/feature_set.py +42 -12
  220. mlrun/feature_store/feature_vector.py +32 -21
  221. mlrun/feature_store/ingestion.py +9 -12
  222. mlrun/feature_store/retrieval/__init__.py +3 -2
  223. mlrun/feature_store/retrieval/base.py +388 -66
  224. mlrun/feature_store/retrieval/dask_merger.py +63 -151
  225. mlrun/feature_store/retrieval/job.py +30 -12
  226. mlrun/feature_store/retrieval/local_merger.py +40 -133
  227. mlrun/feature_store/retrieval/spark_merger.py +129 -127
  228. mlrun/feature_store/retrieval/storey_merger.py +173 -0
  229. mlrun/feature_store/steps.py +132 -15
  230. mlrun/features.py +8 -3
  231. mlrun/frameworks/__init__.py +1 -1
  232. mlrun/frameworks/_common/__init__.py +1 -1
  233. mlrun/frameworks/_common/artifacts_library.py +1 -1
  234. mlrun/frameworks/_common/mlrun_interface.py +1 -1
  235. mlrun/frameworks/_common/model_handler.py +1 -1
  236. mlrun/frameworks/_common/plan.py +1 -1
  237. mlrun/frameworks/_common/producer.py +1 -1
  238. mlrun/frameworks/_common/utils.py +1 -1
  239. mlrun/frameworks/_dl_common/__init__.py +1 -1
  240. mlrun/frameworks/_dl_common/loggers/__init__.py +1 -1
  241. mlrun/frameworks/_dl_common/loggers/logger.py +1 -1
  242. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +1 -1
  243. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +1 -1
  244. mlrun/frameworks/_dl_common/model_handler.py +1 -1
  245. mlrun/frameworks/_dl_common/utils.py +1 -1
  246. mlrun/frameworks/_ml_common/__init__.py +1 -1
  247. mlrun/frameworks/_ml_common/artifacts_library.py +1 -1
  248. mlrun/frameworks/_ml_common/loggers/__init__.py +1 -1
  249. mlrun/frameworks/_ml_common/loggers/logger.py +1 -1
  250. mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +1 -1
  251. mlrun/frameworks/_ml_common/model_handler.py +1 -1
  252. mlrun/frameworks/_ml_common/pkl_model_server.py +13 -1
  253. mlrun/frameworks/_ml_common/plan.py +1 -1
  254. mlrun/frameworks/_ml_common/plans/__init__.py +1 -1
  255. mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +1 -6
  256. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +1 -1
  257. mlrun/frameworks/_ml_common/plans/dataset_plan.py +1 -1
  258. mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +1 -1
  259. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +1 -1
  260. mlrun/frameworks/_ml_common/producer.py +1 -1
  261. mlrun/frameworks/_ml_common/utils.py +1 -1
  262. mlrun/frameworks/auto_mlrun/__init__.py +1 -1
  263. mlrun/frameworks/auto_mlrun/auto_mlrun.py +1 -1
  264. mlrun/frameworks/huggingface/__init__.py +1 -1
  265. mlrun/frameworks/huggingface/model_server.py +1 -1
  266. mlrun/frameworks/lgbm/__init__.py +1 -1
  267. mlrun/frameworks/lgbm/callbacks/__init__.py +1 -1
  268. mlrun/frameworks/lgbm/callbacks/callback.py +1 -1
  269. mlrun/frameworks/lgbm/callbacks/logging_callback.py +1 -1
  270. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +1 -1
  271. mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -1
  272. mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -1
  273. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +1 -1
  274. mlrun/frameworks/lgbm/mlrun_interfaces/model_mlrun_interface.py +1 -1
  275. mlrun/frameworks/lgbm/model_handler.py +1 -1
  276. mlrun/frameworks/lgbm/model_server.py +1 -1
  277. mlrun/frameworks/lgbm/utils.py +1 -1
  278. mlrun/frameworks/onnx/__init__.py +1 -1
  279. mlrun/frameworks/onnx/dataset.py +1 -1
  280. mlrun/frameworks/onnx/mlrun_interface.py +1 -1
  281. mlrun/frameworks/onnx/model_handler.py +1 -1
  282. mlrun/frameworks/onnx/model_server.py +1 -1
  283. mlrun/frameworks/parallel_coordinates.py +1 -1
  284. mlrun/frameworks/pytorch/__init__.py +1 -1
  285. mlrun/frameworks/pytorch/callbacks/__init__.py +1 -1
  286. mlrun/frameworks/pytorch/callbacks/callback.py +1 -1
  287. mlrun/frameworks/pytorch/callbacks/logging_callback.py +1 -1
  288. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +1 -1
  289. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +1 -1
  290. mlrun/frameworks/pytorch/callbacks_handler.py +1 -1
  291. mlrun/frameworks/pytorch/mlrun_interface.py +1 -1
  292. mlrun/frameworks/pytorch/model_handler.py +1 -1
  293. mlrun/frameworks/pytorch/model_server.py +1 -1
  294. mlrun/frameworks/pytorch/utils.py +1 -1
  295. mlrun/frameworks/sklearn/__init__.py +1 -1
  296. mlrun/frameworks/sklearn/estimator.py +1 -1
  297. mlrun/frameworks/sklearn/metric.py +1 -1
  298. mlrun/frameworks/sklearn/metrics_library.py +1 -1
  299. mlrun/frameworks/sklearn/mlrun_interface.py +1 -1
  300. mlrun/frameworks/sklearn/model_handler.py +1 -1
  301. mlrun/frameworks/sklearn/utils.py +1 -1
  302. mlrun/frameworks/tf_keras/__init__.py +1 -1
  303. mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -1
  304. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
  305. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +1 -1
  306. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +1 -1
  307. mlrun/frameworks/tf_keras/mlrun_interface.py +1 -1
  308. mlrun/frameworks/tf_keras/model_handler.py +1 -1
  309. mlrun/frameworks/tf_keras/model_server.py +1 -1
  310. mlrun/frameworks/tf_keras/utils.py +1 -1
  311. mlrun/frameworks/xgboost/__init__.py +1 -1
  312. mlrun/frameworks/xgboost/mlrun_interface.py +1 -1
  313. mlrun/frameworks/xgboost/model_handler.py +1 -1
  314. mlrun/frameworks/xgboost/utils.py +1 -1
  315. mlrun/k8s_utils.py +14 -765
  316. mlrun/kfpops.py +14 -17
  317. mlrun/launcher/__init__.py +13 -0
  318. mlrun/launcher/base.py +406 -0
  319. mlrun/launcher/client.py +159 -0
  320. mlrun/launcher/factory.py +50 -0
  321. mlrun/launcher/local.py +276 -0
  322. mlrun/launcher/remote.py +178 -0
  323. mlrun/lists.py +10 -2
  324. mlrun/mlutils/__init__.py +1 -1
  325. mlrun/mlutils/data.py +1 -1
  326. mlrun/mlutils/models.py +1 -1
  327. mlrun/mlutils/plots.py +1 -1
  328. mlrun/model.py +252 -14
  329. mlrun/model_monitoring/__init__.py +41 -0
  330. mlrun/model_monitoring/features_drift_table.py +1 -1
  331. mlrun/model_monitoring/helpers.py +123 -38
  332. mlrun/model_monitoring/model_endpoint.py +144 -0
  333. mlrun/model_monitoring/model_monitoring_batch.py +310 -259
  334. mlrun/model_monitoring/stores/__init__.py +106 -0
  335. mlrun/model_monitoring/stores/kv_model_endpoint_store.py +448 -0
  336. mlrun/model_monitoring/stores/model_endpoint_store.py +147 -0
  337. mlrun/model_monitoring/stores/models/__init__.py +23 -0
  338. mlrun/model_monitoring/stores/models/base.py +18 -0
  339. mlrun/model_monitoring/stores/models/mysql.py +100 -0
  340. mlrun/model_monitoring/stores/models/sqlite.py +98 -0
  341. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +370 -0
  342. mlrun/model_monitoring/stream_processing_fs.py +239 -271
  343. mlrun/package/__init__.py +163 -0
  344. mlrun/package/context_handler.py +325 -0
  345. mlrun/package/errors.py +47 -0
  346. mlrun/package/packager.py +298 -0
  347. mlrun/{runtimes/package → package/packagers}/__init__.py +3 -1
  348. mlrun/package/packagers/default_packager.py +422 -0
  349. mlrun/package/packagers/numpy_packagers.py +612 -0
  350. mlrun/package/packagers/pandas_packagers.py +968 -0
  351. mlrun/package/packagers/python_standard_library_packagers.py +616 -0
  352. mlrun/package/packagers_manager.py +786 -0
  353. mlrun/package/utils/__init__.py +53 -0
  354. mlrun/package/utils/_archiver.py +226 -0
  355. mlrun/package/utils/_formatter.py +211 -0
  356. mlrun/package/utils/_pickler.py +234 -0
  357. mlrun/package/utils/_supported_format.py +71 -0
  358. mlrun/package/utils/log_hint_utils.py +93 -0
  359. mlrun/package/utils/type_hint_utils.py +298 -0
  360. mlrun/platforms/__init__.py +1 -1
  361. mlrun/platforms/iguazio.py +34 -2
  362. mlrun/platforms/other.py +1 -1
  363. mlrun/projects/__init__.py +1 -1
  364. mlrun/projects/operations.py +14 -9
  365. mlrun/projects/pipelines.py +31 -13
  366. mlrun/projects/project.py +762 -238
  367. mlrun/render.py +49 -19
  368. mlrun/run.py +57 -326
  369. mlrun/runtimes/__init__.py +3 -9
  370. mlrun/runtimes/base.py +247 -784
  371. mlrun/runtimes/constants.py +1 -1
  372. mlrun/runtimes/daskjob.py +45 -41
  373. mlrun/runtimes/funcdoc.py +43 -7
  374. mlrun/runtimes/function.py +66 -656
  375. mlrun/runtimes/function_reference.py +1 -1
  376. mlrun/runtimes/generators.py +1 -1
  377. mlrun/runtimes/kubejob.py +99 -116
  378. mlrun/runtimes/local.py +59 -66
  379. mlrun/runtimes/mpijob/__init__.py +1 -1
  380. mlrun/runtimes/mpijob/abstract.py +13 -15
  381. mlrun/runtimes/mpijob/v1.py +3 -1
  382. mlrun/runtimes/mpijob/v1alpha1.py +1 -1
  383. mlrun/runtimes/nuclio.py +1 -1
  384. mlrun/runtimes/pod.py +51 -26
  385. mlrun/runtimes/remotesparkjob.py +3 -1
  386. mlrun/runtimes/serving.py +12 -4
  387. mlrun/runtimes/sparkjob/__init__.py +1 -2
  388. mlrun/runtimes/sparkjob/abstract.py +44 -31
  389. mlrun/runtimes/sparkjob/spark3job.py +11 -9
  390. mlrun/runtimes/utils.py +61 -42
  391. mlrun/secrets.py +16 -18
  392. mlrun/serving/__init__.py +3 -2
  393. mlrun/serving/merger.py +1 -1
  394. mlrun/serving/remote.py +1 -1
  395. mlrun/serving/routers.py +39 -42
  396. mlrun/serving/server.py +23 -13
  397. mlrun/serving/serving_wrapper.py +1 -1
  398. mlrun/serving/states.py +172 -39
  399. mlrun/serving/utils.py +1 -1
  400. mlrun/serving/v1_serving.py +1 -1
  401. mlrun/serving/v2_serving.py +29 -21
  402. mlrun/utils/__init__.py +1 -2
  403. mlrun/utils/async_http.py +8 -1
  404. mlrun/utils/azure_vault.py +1 -1
  405. mlrun/utils/clones.py +2 -2
  406. mlrun/utils/condition_evaluator.py +65 -0
  407. mlrun/utils/db.py +52 -0
  408. mlrun/utils/helpers.py +188 -13
  409. mlrun/utils/http.py +89 -54
  410. mlrun/utils/logger.py +48 -8
  411. mlrun/utils/model_monitoring.py +132 -100
  412. mlrun/utils/notifications/__init__.py +1 -1
  413. mlrun/utils/notifications/notification/__init__.py +8 -6
  414. mlrun/utils/notifications/notification/base.py +20 -14
  415. mlrun/utils/notifications/notification/console.py +7 -4
  416. mlrun/utils/notifications/notification/git.py +36 -19
  417. mlrun/utils/notifications/notification/ipython.py +10 -8
  418. mlrun/utils/notifications/notification/slack.py +18 -13
  419. mlrun/utils/notifications/notification_pusher.py +377 -56
  420. mlrun/utils/regex.py +6 -1
  421. mlrun/utils/singleton.py +1 -1
  422. mlrun/utils/v3io_clients.py +1 -1
  423. mlrun/utils/vault.py +270 -269
  424. mlrun/utils/version/__init__.py +1 -1
  425. mlrun/utils/version/version.json +2 -2
  426. mlrun/utils/version/version.py +1 -1
  427. {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/METADATA +16 -10
  428. mlrun-1.4.0.dist-info/RECORD +434 -0
  429. mlrun/api/api/endpoints/marketplace.py +0 -257
  430. mlrun/api/crud/marketplace.py +0 -221
  431. mlrun/api/crud/model_monitoring/model_endpoint_store.py +0 -847
  432. mlrun/api/db/filedb/db.py +0 -518
  433. mlrun/api/schemas/marketplace.py +0 -128
  434. mlrun/api/schemas/model_endpoints.py +0 -185
  435. mlrun/db/filedb.py +0 -891
  436. mlrun/feature_store/retrieval/online.py +0 -92
  437. mlrun/model_monitoring/constants.py +0 -67
  438. mlrun/runtimes/package/context_handler.py +0 -711
  439. mlrun/runtimes/sparkjob/spark2job.py +0 -59
  440. mlrun-1.3.3rc1.dist-info/RECORD +0 -381
  441. {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/LICENSE +0 -0
  442. {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/WHEEL +0 -0
  443. {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/entry_points.txt +0 -0
  444. {mlrun-1.3.3rc1.dist-info → mlrun-1.4.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- # Copyright 2018 Iguazio
1
+ # Copyright 2023 Iguazio
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -11,9 +11,681 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- #
15
- from mlrun.k8s_utils import K8sHelper, get_k8s_helper
14
+ import base64
15
+ import hashlib
16
+ import time
17
+ import typing
18
+
19
+ from kubernetes import client, config
20
+ from kubernetes.client.rest import ApiException
21
+
22
+ import mlrun.common.schemas
23
+ import mlrun.config as mlconfig
24
+ import mlrun.errors
25
+ import mlrun.platforms.iguazio
26
+ from mlrun.utils import logger
27
+
28
+ _k8s = None
29
+
30
+
31
+ def get_k8s_helper(namespace=None, silent=True, log=False) -> "K8sHelper":
32
+ """
33
+ Get a k8s helper singleton object
34
+ :param namespace: the namespace to use, if not specified will use the namespace configured in mlrun config
35
+ :param silent: set to true if you're calling this function from a code that might run from remotely (outside of a
36
+ k8s cluster)
37
+ :param log: sometimes we want to avoid logging when executing init_k8s_config
38
+ """
39
+ global _k8s
40
+ if not _k8s:
41
+ _k8s = K8sHelper(namespace, silent=silent, log=log)
42
+ return _k8s
43
+
44
+
45
+ class SecretTypes:
46
+ opaque = "Opaque"
47
+ v3io_fuse = "v3io/fuse"
48
+
49
+
50
+ class K8sHelper:
51
+ def __init__(self, namespace=None, silent=False, log=True):
52
+ self.namespace = namespace or mlconfig.config.namespace
53
+ self.config_file = mlconfig.config.kubernetes.kubeconfig_path or None
54
+ self.running_inside_kubernetes_cluster = False
55
+ try:
56
+ self._init_k8s_config(log)
57
+ self.v1api = client.CoreV1Api()
58
+ self.crdapi = client.CustomObjectsApi()
59
+ except Exception as exc:
60
+ logger.warning(
61
+ "cannot initialize kubernetes client", exc=mlrun.errors.err_to_str(exc)
62
+ )
63
+ if not silent:
64
+ raise
65
+
66
+ def resolve_namespace(self, namespace=None):
67
+ return namespace or self.namespace
68
+
69
+ def _init_k8s_config(self, log=True):
70
+ try:
71
+ config.load_incluster_config()
72
+ self.running_inside_kubernetes_cluster = True
73
+ if log:
74
+ logger.info("using in-cluster config.")
75
+ except Exception:
76
+ try:
77
+ config.load_kube_config(self.config_file)
78
+ if log:
79
+ logger.info("using local kubernetes config.")
80
+ except Exception:
81
+ raise RuntimeError(
82
+ "cannot find local kubernetes config file,"
83
+ " place it in ~/.kube/config or specify it in "
84
+ "KUBECONFIG env var"
85
+ )
86
+
87
+ def is_running_inside_kubernetes_cluster(self):
88
+ return self.running_inside_kubernetes_cluster
89
+
90
+ def list_pods(self, namespace=None, selector="", states=None):
91
+ try:
92
+ resp = self.v1api.list_namespaced_pod(
93
+ self.resolve_namespace(namespace), label_selector=selector
94
+ )
95
+ except ApiException as exc:
96
+ logger.error(f"failed to list pods: {mlrun.errors.err_to_str(exc)}")
97
+ raise exc
98
+
99
+ items = []
100
+ for i in resp.items:
101
+ if not states or i.status.phase in states:
102
+ items.append(i)
103
+ return items
104
+
105
+ def create_pod(self, pod, max_retry=3, retry_interval=3):
106
+ if "pod" in dir(pod):
107
+ pod = pod.pod
108
+ pod.metadata.namespace = self.resolve_namespace(pod.metadata.namespace)
109
+
110
+ retry_count = 0
111
+ while True:
112
+ try:
113
+ resp = self.v1api.create_namespaced_pod(pod.metadata.namespace, pod)
114
+ except ApiException as exc:
115
+
116
+ if retry_count > max_retry:
117
+ logger.error(
118
+ "failed to create pod after max retries",
119
+ retry_count=retry_count,
120
+ exc=mlrun.errors.err_to_str(exc),
121
+ pod=pod,
122
+ )
123
+ raise exc
124
+
125
+ logger.error(
126
+ "failed to create pod", exc=mlrun.errors.err_to_str(exc), pod=pod
127
+ )
128
+
129
+ # known k8s issue, see https://github.com/kubernetes/kubernetes/issues/67761
130
+ if "gke-resource-quotas" in mlrun.errors.err_to_str(exc):
131
+ logger.warning(
132
+ "failed to create pod due to gke resource error, "
133
+ f"sleeping {retry_interval} seconds and retrying"
134
+ )
135
+ retry_count += 1
136
+ time.sleep(retry_interval)
137
+ continue
138
+
139
+ raise exc
140
+ else:
141
+ logger.info(f"Pod {resp.metadata.name} created")
142
+ return resp.metadata.name, resp.metadata.namespace
143
+
144
+ def delete_pod(self, name, namespace=None):
145
+ try:
146
+ api_response = self.v1api.delete_namespaced_pod(
147
+ name,
148
+ self.resolve_namespace(namespace),
149
+ grace_period_seconds=0,
150
+ propagation_policy="Background",
151
+ )
152
+ return api_response
153
+ except ApiException as exc:
154
+ # ignore error if pod is already removed
155
+ if exc.status != 404:
156
+ logger.error(
157
+ f"failed to delete pod: {mlrun.errors.err_to_str(exc)}",
158
+ pod_name=name,
159
+ )
160
+ raise exc
161
+
162
+ def get_pod(self, name, namespace=None, raise_on_not_found=False):
163
+ try:
164
+ api_response = self.v1api.read_namespaced_pod(
165
+ name=name, namespace=self.resolve_namespace(namespace)
166
+ )
167
+ return api_response
168
+ except ApiException as exc:
169
+ if exc.status != 404:
170
+ logger.error(f"failed to get pod: {mlrun.errors.err_to_str(exc)}")
171
+ raise exc
172
+ else:
173
+ if raise_on_not_found:
174
+ raise mlrun.errors.MLRunNotFoundError(f"Pod not found: {name}")
175
+ return None
176
+
177
+ def get_pod_status(self, name, namespace=None):
178
+ return self.get_pod(
179
+ name, namespace, raise_on_not_found=True
180
+ ).status.phase.lower()
181
+
182
+ def delete_crd(self, name, crd_group, crd_version, crd_plural, namespace=None):
183
+ try:
184
+ namespace = self.resolve_namespace(namespace)
185
+ self.crdapi.delete_namespaced_custom_object(
186
+ crd_group,
187
+ crd_version,
188
+ namespace,
189
+ crd_plural,
190
+ name,
191
+ )
192
+ logger.info(
193
+ "Deleted crd object",
194
+ crd_name=name,
195
+ namespace=namespace,
196
+ )
197
+ except ApiException as exc:
198
+
199
+ # ignore error if crd is already removed
200
+ if exc.status != 404:
201
+ logger.error(
202
+ f"failed to delete crd: {mlrun.errors.err_to_str(exc)}",
203
+ crd_name=name,
204
+ crd_group=crd_group,
205
+ crd_version=crd_version,
206
+ crd_plural=crd_plural,
207
+ )
208
+ raise exc
209
+
210
+ def logs(self, name, namespace=None):
211
+ try:
212
+ resp = self.v1api.read_namespaced_pod_log(
213
+ name=name, namespace=self.resolve_namespace(namespace)
214
+ )
215
+ except ApiException as exc:
216
+ logger.error(f"failed to get pod logs: {mlrun.errors.err_to_str(exc)}")
217
+ raise exc
218
+
219
+ return resp
220
+
221
+ def get_logger_pods(self, project, uid, run_kind, namespace=""):
222
+
223
+ # As this file is imported in mlrun.runtimes, we sadly cannot have this import in the top level imports
224
+ # as that will create an import loop.
225
+ # TODO: Fix the import loops already!
226
+ import mlrun.runtimes
227
+
228
+ namespace = self.resolve_namespace(namespace)
229
+ mpijob_crd_version = mlrun.runtimes.utils.resolve_mpijob_crd_version()
230
+ mpijob_role_label = (
231
+ mlrun.runtimes.constants.MPIJobCRDVersions.role_label_by_version(
232
+ mpijob_crd_version
233
+ )
234
+ )
235
+ extra_selectors = {
236
+ "spark": "spark-role=driver",
237
+ "mpijob": f"{mpijob_role_label}=launcher",
238
+ }
239
+
240
+ # TODO: all mlrun labels are sprinkled in a lot of places - they need to all be defined in a central,
241
+ # inclusive place.
242
+ selectors = [
243
+ "mlrun/class",
244
+ f"mlrun/project={project}",
245
+ f"mlrun/uid={uid}",
246
+ ]
247
+
248
+ # In order to make the `list_pods` request return a lighter and quicker result, we narrow the search for
249
+ # the relevant pods using the proper label selector according to the run kind
250
+ if run_kind in extra_selectors:
251
+ selectors.append(extra_selectors[run_kind])
252
+
253
+ selector = ",".join(selectors)
254
+ pods = self.list_pods(namespace, selector=selector)
255
+ if not pods:
256
+ logger.error("no pod matches that uid", uid=uid)
257
+ return
258
+
259
+ return {p.metadata.name: p.status.phase for p in pods}
260
+
261
+ def get_project_vault_secret_name(
262
+ self, project, service_account_name, namespace=""
263
+ ):
264
+ namespace = self.resolve_namespace(namespace)
265
+
266
+ try:
267
+ service_account = self.v1api.read_namespaced_service_account(
268
+ service_account_name, namespace
269
+ )
270
+ except ApiException as exc:
271
+ # It's valid for the service account to not exist. Simply return None
272
+ if exc.status != 404:
273
+ logger.error(
274
+ f"failed to retrieve service accounts: {mlrun.errors.err_to_str(exc)}"
275
+ )
276
+ raise exc
277
+ return None
278
+
279
+ if len(service_account.secrets) > 1:
280
+ raise ValueError(
281
+ f"Service account {service_account_name} has more than one secret"
282
+ )
283
+
284
+ return service_account.secrets[0].name
285
+
286
+ def get_project_secret_name(self, project) -> str:
287
+ return mlconfig.config.secret_stores.kubernetes.project_secret_name.format(
288
+ project=project
289
+ )
290
+
291
+ def get_auth_secret_name(self, access_key: str) -> str:
292
+ hashed_access_key = self._hash_access_key(access_key)
293
+ return mlconfig.config.secret_stores.kubernetes.auth_secret_name.format(
294
+ hashed_access_key=hashed_access_key
295
+ )
296
+
297
+ @staticmethod
298
+ def _hash_access_key(access_key: str):
299
+ return hashlib.sha224(access_key.encode()).hexdigest()
300
+
301
+ def store_project_secrets(
302
+ self, project, secrets, namespace=""
303
+ ) -> (str, typing.Optional[mlrun.common.schemas.SecretEventActions]):
304
+ secret_name = self.get_project_secret_name(project)
305
+ action = self.store_secrets(secret_name, secrets, namespace)
306
+ return secret_name, action
307
+
308
+ def read_auth_secret(self, secret_name, namespace="", raise_on_not_found=False):
309
+ namespace = self.resolve_namespace(namespace)
310
+
311
+ try:
312
+ secret_data = self.v1api.read_namespaced_secret(secret_name, namespace).data
313
+ except ApiException as exc:
314
+ logger.error(
315
+ "Failed to read secret",
316
+ secret_name=secret_name,
317
+ namespace=namespace,
318
+ exc=mlrun.errors.err_to_str(exc),
319
+ )
320
+ if exc.status != 404:
321
+ raise exc
322
+ elif raise_on_not_found:
323
+ raise mlrun.errors.MLRunNotFoundError(
324
+ f"Secret '{secret_name}' was not found in namespace '{namespace}'"
325
+ ) from exc
326
+
327
+ return None, None
328
+
329
+ def _get_secret_value(key):
330
+ if secret_data.get(key):
331
+ return base64.b64decode(secret_data[key]).decode("utf-8")
332
+ else:
333
+ return None
334
+
335
+ username = _get_secret_value(
336
+ mlrun.common.schemas.AuthSecretData.get_field_secret_key("username")
337
+ )
338
+ access_key = _get_secret_value(
339
+ mlrun.common.schemas.AuthSecretData.get_field_secret_key("access_key")
340
+ )
341
+
342
+ return username, access_key
343
+
344
+ def store_auth_secret(
345
+ self, username: str, access_key: str, namespace=""
346
+ ) -> (str, typing.Optional[mlrun.common.schemas.SecretEventActions]):
347
+ """
348
+ Store the given access key as a secret in the cluster. The secret name is generated from the access key
349
+ :return: returns the secret name and the action taken against the secret
350
+ """
351
+ secret_name = self.get_auth_secret_name(access_key)
352
+ secret_data = {
353
+ mlrun.common.schemas.AuthSecretData.get_field_secret_key(
354
+ "username"
355
+ ): username,
356
+ mlrun.common.schemas.AuthSecretData.get_field_secret_key(
357
+ "access_key"
358
+ ): access_key,
359
+ }
360
+ action = self.store_secrets(
361
+ secret_name,
362
+ secret_data,
363
+ namespace,
364
+ type_=SecretTypes.v3io_fuse,
365
+ labels={"mlrun/username": username},
366
+ )
367
+ return secret_name, action
368
+
369
+ def store_secrets(
370
+ self,
371
+ secret_name,
372
+ secrets,
373
+ namespace="",
374
+ type_=SecretTypes.opaque,
375
+ labels: typing.Optional[dict] = None,
376
+ ) -> typing.Optional[mlrun.common.schemas.SecretEventActions]:
377
+ """
378
+ Store secrets in a kubernetes secret object
379
+ :param secret_name: the project secret name
380
+ :param secrets: the secrets to delete
381
+ :param namespace: k8s namespace
382
+ :param type_: k8s secret type
383
+ :param labels: k8s labels for the secret
384
+ :return: returns the action if the secret was created or updated, None if nothing changed
385
+ """
386
+ namespace = self.resolve_namespace(namespace)
387
+ try:
388
+ k8s_secret = self.v1api.read_namespaced_secret(secret_name, namespace)
389
+ except ApiException as exc:
390
+ # If secret doesn't exist, we'll simply create it
391
+ if exc.status != 404:
392
+ logger.error(
393
+ f"failed to retrieve k8s secret: {mlrun.errors.err_to_str(exc)}"
394
+ )
395
+ raise exc
396
+ k8s_secret = client.V1Secret(type=type_)
397
+ k8s_secret.metadata = client.V1ObjectMeta(
398
+ name=secret_name, namespace=namespace, labels=labels
399
+ )
400
+ k8s_secret.string_data = secrets
401
+ self.v1api.create_namespaced_secret(namespace, k8s_secret)
402
+ return mlrun.common.schemas.SecretEventActions.created
403
+
404
+ secret_data = k8s_secret.data.copy()
405
+ for key, value in secrets.items():
406
+ secret_data[key] = base64.b64encode(value.encode()).decode("utf-8")
407
+
408
+ k8s_secret.data = secret_data
409
+ self.v1api.replace_namespaced_secret(secret_name, namespace, k8s_secret)
410
+ return mlrun.common.schemas.SecretEventActions.updated
411
+
412
+ def load_secret(self, secret_name, namespace=""):
413
+ namespace = namespace or self.resolve_namespace(namespace)
414
+
415
+ try:
416
+ k8s_secret = self.v1api.read_namespaced_secret(secret_name, namespace)
417
+ except ApiException:
418
+ return None
419
+
420
+ return k8s_secret.data
421
+
422
+ def delete_project_secrets(
423
+ self, project, secrets, namespace=""
424
+ ) -> (str, typing.Optional[mlrun.common.schemas.SecretEventActions]):
425
+ """
426
+ Delete secrets from a kubernetes secret object
427
+ :return: returns the secret name and the action taken against the secret
428
+ """
429
+ secret_name = self.get_project_secret_name(project)
430
+ action = self.delete_secrets(secret_name, secrets, namespace)
431
+ return secret_name, action
432
+
433
+ def delete_auth_secret(self, secret_ref: str, namespace=""):
434
+ self.delete_secrets(secret_ref, {}, namespace)
435
+
436
+ def delete_secrets(
437
+ self, secret_name, secrets, namespace=""
438
+ ) -> typing.Optional[mlrun.common.schemas.SecretEventActions]:
439
+ """
440
+ Delete secrets from a kubernetes secret object
441
+ :param secret_name: the project secret name
442
+ :param secrets: the secrets to delete
443
+ :param namespace: k8s namespace
444
+ :return: returns the action if the secret was deleted or updated, None if nothing changed
445
+ """
446
+ namespace = self.resolve_namespace(namespace)
447
+
448
+ try:
449
+ k8s_secret = self.v1api.read_namespaced_secret(secret_name, namespace)
450
+ except ApiException as exc:
451
+ if exc.status == 404:
452
+ logger.info(
453
+ "Project secret does not exist, nothing to delete.",
454
+ secret_name=secret_name,
455
+ )
456
+ return None
457
+ else:
458
+ logger.error(
459
+ f"failed to retrieve k8s secret: {mlrun.errors.err_to_str(exc)}"
460
+ )
461
+ raise exc
462
+
463
+ secret_data = {}
464
+ if secrets:
465
+ secret_data = k8s_secret.data.copy()
466
+ for secret in secrets:
467
+ secret_data.pop(secret, None)
468
+
469
+ if secret_data:
470
+ k8s_secret.data = secret_data
471
+ self.v1api.replace_namespaced_secret(secret_name, namespace, k8s_secret)
472
+ return mlrun.common.schemas.SecretEventActions.updated
473
+
474
+ self.v1api.delete_namespaced_secret(secret_name, namespace)
475
+ return mlrun.common.schemas.SecretEventActions.deleted
476
+
477
+ def _get_project_secrets_raw_data(self, project, namespace=""):
478
+ secret_name = self.get_project_secret_name(project)
479
+ return self._get_secret_raw_data(secret_name, namespace)
480
+
481
+ def _get_secret_raw_data(self, secret_name, namespace=""):
482
+ namespace = self.resolve_namespace(namespace)
483
+
484
+ try:
485
+ k8s_secret = self.v1api.read_namespaced_secret(secret_name, namespace)
486
+ except ApiException:
487
+ return None
488
+
489
+ return k8s_secret.data
490
+
491
+ def get_project_secret_keys(self, project, namespace="", filter_internal=False):
492
+ secrets_data = self._get_project_secrets_raw_data(project, namespace)
493
+ if not secrets_data:
494
+ return []
495
+
496
+ secret_keys = list(secrets_data.keys())
497
+ if filter_internal:
498
+ secret_keys = list(
499
+ filter(lambda key: not key.startswith("mlrun."), secret_keys)
500
+ )
501
+ return secret_keys
502
+
503
+ def get_project_secret_data(self, project, secret_keys=None, namespace=""):
504
+ secrets_data = self._get_project_secrets_raw_data(project, namespace)
505
+ return self._decode_secret_data(secrets_data, secret_keys)
506
+
507
+ def get_secret_data(self, secret_name, namespace=""):
508
+ secrets_data = self._get_secret_raw_data(secret_name, namespace)
509
+ return self._decode_secret_data(secrets_data)
510
+
511
+ def _decode_secret_data(self, secrets_data, secret_keys=None):
512
+ results = {}
513
+ if not secrets_data:
514
+ return results
515
+
516
+ # If not asking for specific keys, return all
517
+ secret_keys = secret_keys or secrets_data.keys()
518
+
519
+ for key in secret_keys:
520
+ encoded_value = secrets_data.get(key)
521
+ if encoded_value:
522
+ results[key] = base64.b64decode(secrets_data[key]).decode("utf-8")
523
+ return results
524
+
525
+
526
+ class BasePod:
527
+ def __init__(
528
+ self,
529
+ task_name="",
530
+ image=None,
531
+ command=None,
532
+ args=None,
533
+ namespace="",
534
+ kind="job",
535
+ project=None,
536
+ default_pod_spec_attributes=None,
537
+ resources=None,
538
+ ):
539
+ self.namespace = namespace
540
+ self.name = ""
541
+ self.task_name = task_name
542
+ self.image = image
543
+ self.command = command
544
+ self.args = args
545
+ self._volumes = []
546
+ self._mounts = []
547
+ self.env = None
548
+ self.node_selector = None
549
+ self.project = project or mlrun.mlconf.default_project
550
+ self._labels = {
551
+ "mlrun/task-name": task_name,
552
+ "mlrun/class": kind,
553
+ "mlrun/project": self.project,
554
+ }
555
+ self._annotations = {}
556
+ self._init_containers = []
557
+ # will be applied on the pod spec only when calling .pod(), allows to override spec attributes
558
+ self.default_pod_spec_attributes = default_pod_spec_attributes
559
+ self.resources = resources
560
+
561
+ @property
562
+ def pod(self):
563
+ return self._get_spec()
564
+
565
+ @property
566
+ def init_containers(self):
567
+ return self._init_containers
568
+
569
+ @init_containers.setter
570
+ def init_containers(self, containers):
571
+ self._init_containers = containers
572
+
573
+ def append_init_container(
574
+ self,
575
+ image,
576
+ command=None,
577
+ args=None,
578
+ env=None,
579
+ image_pull_policy="IfNotPresent",
580
+ name="init",
581
+ ):
582
+ if isinstance(env, dict):
583
+ env = [client.V1EnvVar(name=k, value=v) for k, v in env.items()]
584
+ self._init_containers.append(
585
+ client.V1Container(
586
+ name=name,
587
+ image=image,
588
+ env=env,
589
+ command=command,
590
+ args=args,
591
+ image_pull_policy=image_pull_policy,
592
+ )
593
+ )
594
+
595
+ def add_label(self, key, value):
596
+ self._labels[key] = str(value)
597
+
598
+ def add_annotation(self, key, value):
599
+ self._annotations[key] = str(value)
600
+
601
+ def add_volume(self, volume: client.V1Volume, mount_path, name=None, sub_path=None):
602
+ self._mounts.append(
603
+ client.V1VolumeMount(
604
+ name=name or volume.name, mount_path=mount_path, sub_path=sub_path
605
+ )
606
+ )
607
+ self._volumes.append(volume)
608
+
609
+ def mount_empty(self, name="empty", mount_path="/empty"):
610
+ self.add_volume(
611
+ client.V1Volume(name=name, empty_dir=client.V1EmptyDirVolumeSource()),
612
+ mount_path=mount_path,
613
+ )
614
+
615
+ def mount_v3io(
616
+ self, name="v3io", remote="~/", mount_path="/User", access_key="", user=""
617
+ ):
618
+ self.add_volume(
619
+ mlrun.platforms.iguazio.v3io_to_vol(name, remote, access_key, user),
620
+ mount_path=mount_path,
621
+ name=name,
622
+ )
623
+
624
+ def mount_cfgmap(self, name, path="/config"):
625
+ self.add_volume(
626
+ client.V1Volume(
627
+ name=name, config_map=client.V1ConfigMapVolumeSource(name=name)
628
+ ),
629
+ mount_path=path,
630
+ )
631
+
632
+ def mount_secret(self, name, path="/secret", items=None, sub_path=None):
633
+ self.add_volume(
634
+ client.V1Volume(
635
+ name=name,
636
+ secret=client.V1SecretVolumeSource(
637
+ secret_name=name,
638
+ items=items,
639
+ ),
640
+ ),
641
+ mount_path=path,
642
+ sub_path=sub_path,
643
+ )
644
+
645
+ def set_node_selector(self, node_selector: typing.Optional[typing.Dict[str, str]]):
646
+ self.node_selector = node_selector
647
+
648
+ def _get_spec(self, template=False):
649
+
650
+ pod_obj = client.V1PodTemplate if template else client.V1Pod
651
+
652
+ if self.env and isinstance(self.env, dict):
653
+ env = [client.V1EnvVar(name=k, value=v) for k, v in self.env.items()]
654
+ else:
655
+ env = self.env
656
+ container = client.V1Container(
657
+ name="base",
658
+ image=self.image,
659
+ env=env,
660
+ command=self.command,
661
+ args=self.args,
662
+ volume_mounts=self._mounts,
663
+ resources=self.resources,
664
+ )
665
+
666
+ pod_spec = client.V1PodSpec(
667
+ containers=[container],
668
+ restart_policy="Never",
669
+ volumes=self._volumes,
670
+ node_selector=self.node_selector,
671
+ )
672
+
673
+ # if attribute isn't defined use default pod spec attributes
674
+ for key, val in self.default_pod_spec_attributes.items():
675
+ if not getattr(pod_spec, key, None):
676
+ setattr(pod_spec, key, val)
16
677
 
678
+ for init_containers in self._init_containers:
679
+ init_containers.volume_mounts = self._mounts
680
+ pod_spec.init_containers = self._init_containers
17
681
 
18
- def get_k8s() -> K8sHelper:
19
- return get_k8s_helper(silent=True)
682
+ pod = pod_obj(
683
+ metadata=client.V1ObjectMeta(
684
+ generate_name=f"{self.task_name}-",
685
+ namespace=self.namespace,
686
+ labels=self._labels,
687
+ annotations=self._annotations,
688
+ ),
689
+ spec=pod_spec,
690
+ )
691
+ return pod
@@ -1,4 +1,4 @@
1
- # Copyright 2018 Iguazio
1
+ # Copyright 2023 Iguazio
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2018 Iguazio
1
+ # Copyright 2023 Iguazio
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.