mage-ai 0.9.44__py3-none-any.whl → 0.9.46__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 mage-ai might be problematic. Click here for more details.

Files changed (540) hide show
  1. mage_ai/api/constants.py +2 -0
  2. mage_ai/api/operations/base.py +208 -12
  3. mage_ai/api/policies/BasePolicy.py +3 -3
  4. mage_ai/api/policies/ComputeClusterPolicy.py +96 -0
  5. mage_ai/api/policies/ComputeConnectionPolicy.py +74 -0
  6. mage_ai/api/policies/ComputeServicePolicy.py +50 -0
  7. mage_ai/api/policies/DownloadPolicy.py +29 -0
  8. mage_ai/api/policies/GitCustomBranchPolicy.py +1 -0
  9. mage_ai/api/policies/GlobalHookPolicy.py +126 -0
  10. mage_ai/api/policies/OauthPolicy.py +56 -7
  11. mage_ai/api/policies/ProjectPolicy.py +1 -0
  12. mage_ai/api/policies/RolePolicy.py +12 -1
  13. mage_ai/api/presenters/ComputeClusterPresenter.py +19 -0
  14. mage_ai/api/presenters/ComputeConnectionPresenter.py +26 -0
  15. mage_ai/api/presenters/ComputeServicePresenter.py +15 -0
  16. mage_ai/api/presenters/DownloadPresenter.py +13 -0
  17. mage_ai/api/presenters/GlobalHookPresenter.py +74 -0
  18. mage_ai/api/presenters/OauthPresenter.py +1 -0
  19. mage_ai/api/presenters/PipelinePresenter.py +1 -0
  20. mage_ai/api/presenters/ProjectPresenter.py +1 -0
  21. mage_ai/api/presenters/SparkApplicationPresenter.py +2 -0
  22. mage_ai/api/presenters/WorkspacePresenter.py +22 -22
  23. mage_ai/api/resources/AsyncBaseResource.py +39 -0
  24. mage_ai/api/resources/BackfillResource.py +1 -0
  25. mage_ai/api/resources/BlockResource.py +57 -0
  26. mage_ai/api/resources/ClusterResource.py +1 -1
  27. mage_ai/api/resources/ComputeClusterResource.py +109 -0
  28. mage_ai/api/resources/ComputeConnectionResource.py +103 -0
  29. mage_ai/api/resources/ComputeServiceResource.py +35 -0
  30. mage_ai/api/resources/DownloadResource.py +56 -0
  31. mage_ai/api/resources/ExecutionStateResource.py +1 -1
  32. mage_ai/api/resources/GitBranchResource.py +35 -29
  33. mage_ai/api/resources/GitCustomBranchResource.py +9 -0
  34. mage_ai/api/resources/GlobalHookResource.py +192 -0
  35. mage_ai/api/resources/KernelResource.py +10 -0
  36. mage_ai/api/resources/OauthResource.py +60 -98
  37. mage_ai/api/resources/PipelineResource.py +4 -4
  38. mage_ai/api/resources/PipelineScheduleResource.py +37 -16
  39. mage_ai/api/resources/ProjectResource.py +5 -3
  40. mage_ai/api/resources/SessionResource.py +24 -9
  41. mage_ai/api/resources/SparkApplicationResource.py +5 -5
  42. mage_ai/api/resources/SparkEnvironmentResource.py +1 -2
  43. mage_ai/api/resources/SparkExecutorResource.py +1 -2
  44. mage_ai/api/resources/SparkJobResource.py +3 -6
  45. mage_ai/api/resources/SparkSqlResource.py +6 -11
  46. mage_ai/api/resources/SparkStageAttemptResource.py +2 -3
  47. mage_ai/api/resources/SparkStageAttemptTaskResource.py +1 -2
  48. mage_ai/api/resources/SparkStageAttemptTaskSummaryResource.py +1 -2
  49. mage_ai/api/resources/SparkStageResource.py +3 -6
  50. mage_ai/api/resources/SparkThreadResource.py +1 -2
  51. mage_ai/api/resources/UserResource.py +32 -31
  52. mage_ai/api/resources/mixins/spark.py +25 -4
  53. mage_ai/authentication/oauth/constants.py +4 -0
  54. mage_ai/authentication/oauth2.py +1 -3
  55. mage_ai/authentication/permissions/constants.py +4 -0
  56. mage_ai/authentication/providers/__init__.py +0 -0
  57. mage_ai/authentication/providers/active_directory.py +136 -0
  58. mage_ai/authentication/providers/constants.py +17 -0
  59. mage_ai/authentication/providers/ghe.py +81 -0
  60. mage_ai/authentication/providers/google.py +86 -0
  61. mage_ai/authentication/providers/oauth.py +60 -0
  62. mage_ai/authentication/providers/okta.py +101 -0
  63. mage_ai/authentication/providers/sso.py +20 -0
  64. mage_ai/authentication/providers/utils.py +12 -0
  65. mage_ai/cluster_manager/aws/emr_cluster_manager.py +2 -1
  66. mage_ai/cluster_manager/workspace/base.py +7 -3
  67. mage_ai/data_integrations/destinations/constants.py +2 -0
  68. mage_ai/data_preparation/executors/block_executor.py +3 -0
  69. mage_ai/data_preparation/executors/pipeline_executor.py +9 -0
  70. mage_ai/data_preparation/git/__init__.py +3 -3
  71. mage_ai/data_preparation/git/api.py +69 -35
  72. mage_ai/data_preparation/models/block/__init__.py +95 -60
  73. mage_ai/data_preparation/models/block/data_integration/data.py +1 -1
  74. mage_ai/data_preparation/models/block/dbt/block_sql.py +95 -1
  75. mage_ai/data_preparation/models/block/dbt/utils.py +6 -0
  76. mage_ai/data_preparation/models/block/spark/mixins.py +82 -34
  77. mage_ai/data_preparation/models/download/__init__.py +8 -0
  78. mage_ai/data_preparation/models/global_hooks/__init__.py +0 -0
  79. mage_ai/data_preparation/models/global_hooks/constants.py +44 -0
  80. mage_ai/data_preparation/models/global_hooks/models.py +928 -0
  81. mage_ai/data_preparation/models/global_hooks/utils.py +21 -0
  82. mage_ai/data_preparation/models/pipeline.py +82 -6
  83. mage_ai/data_preparation/models/pipelines/models.py +16 -0
  84. mage_ai/data_preparation/models/project/__init__.py +6 -0
  85. mage_ai/data_preparation/models/project/constants.py +1 -0
  86. mage_ai/data_preparation/models/project/models.py +12 -0
  87. mage_ai/data_preparation/repo_manager.py +23 -1
  88. mage_ai/data_preparation/templates/callbacks/base.jinja +4 -0
  89. mage_ai/data_preparation/templates/data_exporters/streaming/kafka.yaml +1 -0
  90. mage_ai/data_preparation/templates/data_loaders/streaming/activemq.yaml +6 -0
  91. mage_ai/data_preparation/templates/data_loaders/streaming/kafka.yaml +1 -0
  92. mage_ai/data_preparation/templates/data_loaders/streaming/nats.yaml +20 -0
  93. mage_ai/data_preparation/templates/repo/io_config.yaml +2 -2
  94. mage_ai/io/duckdb.py +0 -1
  95. mage_ai/orchestration/concurrency.py +8 -1
  96. mage_ai/orchestration/db/models/schedules.py +23 -2
  97. mage_ai/orchestration/pipeline_scheduler.py +168 -105
  98. mage_ai/orchestration/queue/process_queue.py +9 -1
  99. mage_ai/orchestration/triggers/api.py +11 -3
  100. mage_ai/orchestration/triggers/constants.py +1 -0
  101. mage_ai/orchestration/triggers/utils.py +23 -0
  102. mage_ai/server/active_kernel.py +37 -4
  103. mage_ai/server/api/downloads.py +76 -1
  104. mage_ai/server/api/triggers.py +1 -0
  105. mage_ai/server/constants.py +1 -1
  106. mage_ai/server/frontend_dist/404.html +2 -2
  107. mage_ai/server/frontend_dist/_next/static/9jB4XPuz6BzxBcG9VNao5/_buildManifest.js +1 -0
  108. mage_ai/server/frontend_dist/_next/static/chunks/1749-9a6276b2918fdae1.js +1 -0
  109. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/7519-8c29bbb92e03cc77.js → frontend_dist/_next/static/chunks/1845-5ce774d5ab81ed57.js} +1 -1
  110. mage_ai/server/frontend_dist/_next/static/chunks/1952-ac7722e8b1ab88fe.js +1 -0
  111. mage_ai/server/frontend_dist/_next/static/chunks/3419-f8d518d024e7b5c8.js +1 -0
  112. mage_ai/server/frontend_dist/_next/static/chunks/4267-fd4d8049e83178de.js +1 -0
  113. mage_ai/server/frontend_dist/_next/static/chunks/4366-93e09e5a4a7e182c.js +1 -0
  114. mage_ai/server/frontend_dist/_next/static/chunks/5457-949640f4037bf12f.js +1 -0
  115. mage_ai/server/frontend_dist/_next/static/chunks/5499-76cf8f023c6b0985.js +1 -0
  116. mage_ai/server/frontend_dist/_next/static/chunks/553-7f7919e14392ca67.js +1 -0
  117. mage_ai/server/frontend_dist/_next/static/chunks/5638-a65610405a70961c.js +1 -0
  118. mage_ai/server/frontend_dist/_next/static/chunks/5810-12eadc488265d55b.js +1 -0
  119. mage_ai/server/frontend_dist/_next/static/chunks/5820-28adeabb5cda2b96.js +1 -0
  120. mage_ai/server/frontend_dist/_next/static/chunks/595-0d174b1f9fbfce4f.js +1 -0
  121. mage_ai/server/frontend_dist/_next/static/chunks/600-705fe234320ec5de.js +1 -0
  122. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/3122-f27de34d0b5426af.js → frontend_dist/_next/static/chunks/6285-e9b45335bfb9ccaf.js} +1 -1
  123. mage_ai/server/frontend_dist/_next/static/chunks/6333-bc1b433b428a9095.js +1 -0
  124. mage_ai/server/frontend_dist/_next/static/chunks/{5397-b5f2e477acc6bd6b.js → 6965-c613d1834c8ed92d.js} +1 -1
  125. mage_ai/server/frontend_dist/_next/static/chunks/{7022-18fde36eb46e1d65.js → 7022-070ec0144a4d029c.js} +1 -1
  126. mage_ai/server/frontend_dist/_next/static/chunks/722-a1584445357a276c.js +1 -0
  127. mage_ai/server/frontend_dist/_next/static/chunks/{7858-c83d25349d0e980f.js → 7858-d9df72e95e438284.js} +1 -1
  128. mage_ai/server/frontend_dist/_next/static/chunks/8264-0d582a6ca33c3dfa.js +1 -0
  129. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/3684-cbda680fd8927d07.js → frontend_dist/_next/static/chunks/8432-f191e39f9b5893f2.js} +1 -1
  130. mage_ai/server/frontend_dist/_next/static/chunks/90-a7308bae028d7001.js +1 -0
  131. mage_ai/server/frontend_dist/_next/static/chunks/9264-1d4f0327d42fed91.js +1 -0
  132. mage_ai/server/frontend_dist/_next/static/chunks/9618-2c5045255ac5a6e7.js +1 -0
  133. mage_ai/server/frontend_dist/_next/static/chunks/{976-27c4eed1c9b20c44.js → 976-18c98af60b76f1a7.js} +1 -1
  134. mage_ai/server/frontend_dist/_next/static/chunks/framework-22b71764bf44ede4.js +1 -0
  135. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-ebef928183f9a3bb.js +1 -0
  136. mage_ai/server/frontend_dist/_next/static/chunks/pages/block-layout-a24cb24b6f08bbc9.js +1 -0
  137. mage_ai/server/frontend_dist/_next/static/chunks/pages/compute-419775ca1293b354.js +1 -0
  138. mage_ai/server/frontend_dist/_next/static/chunks/pages/files-0f2d4be6fdca86ca.js +1 -0
  139. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-data-products/{[...slug]-3f6fc312f67ff72e.js → [...slug]-cfd68e760ae00958.js} +1 -1
  140. mage_ai/server/frontend_dist/_next/static/chunks/pages/{global-data-products-f4cd03036c3e8723.js → global-data-products-c3b79ef31007f95b.js} +1 -1
  141. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-hooks/[...slug]-77edfa32d000e88b.js +1 -0
  142. mage_ai/server/frontend_dist/_next/static/chunks/pages/global-hooks-e561ae38cf5592e8.js +1 -0
  143. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/files-449a022f2f0f2d94.js +1 -0
  144. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/settings-60845f0b59142f32.js +1 -0
  145. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-1d9b298fdceabbf1.js → frontend_dist/_next/static/chunks/pages/manage/users/[user]-9384c5f1efa2ac18.js} +1 -1
  146. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/new-abd8571907664fdf.js +1 -0
  147. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/{users-a7c970122a10afdc.js → users-28a930b148d99766.js} +1 -1
  148. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-f83deb790548693b.js +1 -0
  149. mage_ai/server/frontend_dist/_next/static/chunks/pages/oauth-8bb62c4f6a511c43.js +1 -0
  150. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-f0c40645f385f23f.js +1 -0
  151. mage_ai/server/frontend_dist/_next/static/chunks/pages/{pipeline-runs-c79819d6826e5416.js → pipeline-runs-b35d37bfba8fbccc.js} +1 -1
  152. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-10e9a2d19541caa2.js +1 -0
  153. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c8d3a5289ab93f88.js +1 -0
  154. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-571c0962333b92f0.js +1 -0
  155. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-ff7e9108502f5716.js +1 -0
  156. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-a52d2d3e0c2978f4.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-ef680455ae54ccbe.js} +1 -1
  157. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-ddddcddd2f74b4f6.js +1 -0
  158. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-4a238307feddb522.js +1 -0
  159. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-e051057d9fe94f23.js +1 -0
  160. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs/{[run]-4977276c8f84b5f4.js → [run]-0691711636fa95c7.js} +1 -1
  161. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-ce717786f31e8f04.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-2d20b2cd08907afd.js} +1 -1
  162. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-2914e326a5f1ffe0.js +1 -0
  163. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-b75bf17498e87354.js +1 -0
  164. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-3a7500e6e53084d3.js +1 -0
  165. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-c0e551d265a8d467.js +1 -0
  166. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/{[pipeline]-35fe7762cb83a733.js → [pipeline]-02c843b9c8418bb5.js} +1 -1
  167. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-e47db5c3eaf683af.js +1 -0
  168. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/profile-55ac955dfa9a5a8d.js +1 -0
  169. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-d6a62284c7c99cb3.js → [...slug]-b78b1be5b9ed84b9.js} +1 -1
  170. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{permissions-b1389695f758c32b.js → permissions-37b78a436eeab258.js} +1 -1
  171. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-29c92a9bc54ae5cd.js +1 -0
  172. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-0bdb66265286ab22.js → [...slug]-db05a80d18c168e5.js} +1 -1
  173. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{roles-e04e18fc295ca76a.js → roles-f55c77e4f46c8d33.js} +1 -1
  174. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-2a1f8737561fdd94.js +1 -0
  175. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users/{[...slug]-0267358c91122109.js → [...slug]-e3bf6e5d8bb250c4.js} +1 -1
  176. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-50fed18bb9b8d142.js → users-20f0a050a42a015d.js} +1 -1
  177. mage_ai/server/frontend_dist/_next/static/chunks/pages/{settings-56f83205752b1323.js → settings-0f0121db7f5ff93d.js} +1 -1
  178. mage_ai/server/frontend_dist/_next/static/chunks/pages/sign-in-99e2748e3c1d57a3.js +1 -0
  179. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/templates/[...slug]-9370551ffa462144.js → frontend_dist/_next/static/chunks/pages/templates/[...slug]-f44ccd1499ffd23a.js} +1 -1
  180. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/templates-3cff90df13a1a755.js → frontend_dist/_next/static/chunks/pages/templates-1bfaa1c50e844813.js} +1 -1
  181. mage_ai/server/frontend_dist/_next/static/chunks/pages/terminal-ed121e305169cf1c.js +1 -0
  182. mage_ai/server/frontend_dist/_next/static/chunks/pages/test-9ae68758102cc843.js +1 -0
  183. mage_ai/server/frontend_dist/_next/static/chunks/pages/{triggers-ffaab4c013e62ba1.js → triggers-572d82d6eb7a5d43.js} +1 -1
  184. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-2d26d80370a2e481.js +1 -0
  185. mage_ai/server/frontend_dist/block-layout.html +2 -2
  186. mage_ai/server/frontend_dist/compute.html +5 -5
  187. mage_ai/server/frontend_dist/files.html +5 -5
  188. mage_ai/server/frontend_dist/global-data-products/[...slug].html +5 -5
  189. mage_ai/server/frontend_dist/global-data-products.html +5 -5
  190. mage_ai/server/frontend_dist/global-hooks/[...slug].html +24 -0
  191. mage_ai/server/frontend_dist/global-hooks.html +24 -0
  192. mage_ai/server/frontend_dist/index.html +2 -2
  193. mage_ai/server/frontend_dist/manage/files.html +5 -5
  194. mage_ai/server/frontend_dist/manage/settings.html +5 -5
  195. mage_ai/server/frontend_dist/manage/users/[user].html +5 -5
  196. mage_ai/server/frontend_dist/manage/users/new.html +5 -5
  197. mage_ai/server/frontend_dist/manage/users.html +5 -5
  198. mage_ai/server/frontend_dist/manage.html +5 -5
  199. mage_ai/server/frontend_dist/oauth.html +4 -4
  200. mage_ai/server/frontend_dist/overview.html +5 -5
  201. mage_ai/server/frontend_dist/pipeline-runs.html +5 -5
  202. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +5 -5
  203. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +5 -5
  204. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +5 -5
  205. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  206. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +5 -5
  207. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +5 -5
  208. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +5 -5
  209. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +5 -5
  210. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +5 -5
  211. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +5 -5
  212. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +5 -5
  213. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +5 -5
  214. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +5 -5
  215. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +5 -5
  216. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  217. mage_ai/server/frontend_dist/pipelines.html +5 -5
  218. mage_ai/server/frontend_dist/settings/account/profile.html +5 -5
  219. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +5 -5
  220. mage_ai/server/frontend_dist/settings/workspace/permissions.html +5 -5
  221. mage_ai/server/frontend_dist/settings/workspace/preferences.html +5 -5
  222. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +5 -5
  223. mage_ai/server/frontend_dist/settings/workspace/roles.html +5 -5
  224. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +5 -5
  225. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +5 -5
  226. mage_ai/server/frontend_dist/settings/workspace/users.html +5 -5
  227. mage_ai/server/frontend_dist/settings.html +2 -2
  228. mage_ai/server/frontend_dist/sign-in.html +17 -17
  229. mage_ai/server/frontend_dist/templates/[...slug].html +5 -5
  230. mage_ai/server/frontend_dist/templates.html +5 -5
  231. mage_ai/server/frontend_dist/terminal.html +5 -5
  232. mage_ai/server/frontend_dist/test.html +15 -15
  233. mage_ai/server/frontend_dist/triggers.html +5 -5
  234. mage_ai/server/frontend_dist/version-control.html +5 -5
  235. mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
  236. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1749-9a6276b2918fdae1.js +1 -0
  237. mage_ai/server/{frontend_dist/_next/static/chunks/7519-8c29bbb92e03cc77.js → frontend_dist_base_path_template/_next/static/chunks/1845-5ce774d5ab81ed57.js} +1 -1
  238. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1952-ac7722e8b1ab88fe.js +1 -0
  239. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3419-f8d518d024e7b5c8.js +1 -0
  240. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4267-fd4d8049e83178de.js +1 -0
  241. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4366-93e09e5a4a7e182c.js +1 -0
  242. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5457-949640f4037bf12f.js +1 -0
  243. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5499-76cf8f023c6b0985.js +1 -0
  244. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/553-7f7919e14392ca67.js +1 -0
  245. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5638-a65610405a70961c.js +1 -0
  246. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5810-12eadc488265d55b.js +1 -0
  247. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5820-28adeabb5cda2b96.js +1 -0
  248. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/595-0d174b1f9fbfce4f.js +1 -0
  249. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/600-705fe234320ec5de.js +1 -0
  250. mage_ai/server/{frontend_dist/_next/static/chunks/3122-f27de34d0b5426af.js → frontend_dist_base_path_template/_next/static/chunks/6285-e9b45335bfb9ccaf.js} +1 -1
  251. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6333-bc1b433b428a9095.js +1 -0
  252. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{5397-b5f2e477acc6bd6b.js → 6965-c613d1834c8ed92d.js} +1 -1
  253. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{7022-18fde36eb46e1d65.js → 7022-070ec0144a4d029c.js} +1 -1
  254. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/722-a1584445357a276c.js +1 -0
  255. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{7858-c83d25349d0e980f.js → 7858-d9df72e95e438284.js} +1 -1
  256. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8264-0d582a6ca33c3dfa.js +1 -0
  257. mage_ai/server/{frontend_dist/_next/static/chunks/3684-cbda680fd8927d07.js → frontend_dist_base_path_template/_next/static/chunks/8432-f191e39f9b5893f2.js} +1 -1
  258. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/90-a7308bae028d7001.js +1 -0
  259. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-1d4f0327d42fed91.js +1 -0
  260. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9618-2c5045255ac5a6e7.js +1 -0
  261. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{976-27c4eed1c9b20c44.js → 976-18c98af60b76f1a7.js} +1 -1
  262. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/framework-22b71764bf44ede4.js +1 -0
  263. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-ebef928183f9a3bb.js +1 -0
  264. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/block-layout-a24cb24b6f08bbc9.js +1 -0
  265. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/compute-419775ca1293b354.js +1 -0
  266. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-0f2d4be6fdca86ca.js +1 -0
  267. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-data-products/{[...slug]-3f6fc312f67ff72e.js → [...slug]-cfd68e760ae00958.js} +1 -1
  268. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{global-data-products-f4cd03036c3e8723.js → global-data-products-c3b79ef31007f95b.js} +1 -1
  269. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks/[...slug]-77edfa32d000e88b.js +1 -0
  270. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/global-hooks-e561ae38cf5592e8.js +1 -0
  271. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/files-449a022f2f0f2d94.js +1 -0
  272. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/settings-60845f0b59142f32.js +1 -0
  273. mage_ai/server/{frontend_dist/_next/static/chunks/pages/manage/users/[user]-1d9b298fdceabbf1.js → frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/[user]-9384c5f1efa2ac18.js} +1 -1
  274. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/new-abd8571907664fdf.js +1 -0
  275. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/{users-a7c970122a10afdc.js → users-28a930b148d99766.js} +1 -1
  276. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-f83deb790548693b.js +1 -0
  277. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/oauth-8bb62c4f6a511c43.js +1 -0
  278. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-f0c40645f385f23f.js +1 -0
  279. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{pipeline-runs-c79819d6826e5416.js → pipeline-runs-b35d37bfba8fbccc.js} +1 -1
  280. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-10e9a2d19541caa2.js +1 -0
  281. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c8d3a5289ab93f88.js +1 -0
  282. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-571c0962333b92f0.js +1 -0
  283. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-ff7e9108502f5716.js +1 -0
  284. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-a52d2d3e0c2978f4.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-ef680455ae54ccbe.js} +1 -1
  285. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-ddddcddd2f74b4f6.js +1 -0
  286. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-4a238307feddb522.js +1 -0
  287. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-e051057d9fe94f23.js +1 -0
  288. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs/{[run]-4977276c8f84b5f4.js → [run]-0691711636fa95c7.js} +1 -1
  289. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/runs-ce717786f31e8f04.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/runs-2d20b2cd08907afd.js} +1 -1
  290. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-2914e326a5f1ffe0.js +1 -0
  291. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-b75bf17498e87354.js +1 -0
  292. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-3a7500e6e53084d3.js +1 -0
  293. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-c0e551d265a8d467.js +1 -0
  294. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/{[pipeline]-35fe7762cb83a733.js → [pipeline]-02c843b9c8418bb5.js} +1 -1
  295. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-e47db5c3eaf683af.js +1 -0
  296. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-55ac955dfa9a5a8d.js +1 -0
  297. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/permissions/{[...slug]-d6a62284c7c99cb3.js → [...slug]-b78b1be5b9ed84b9.js} +1 -1
  298. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{permissions-b1389695f758c32b.js → permissions-37b78a436eeab258.js} +1 -1
  299. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-29c92a9bc54ae5cd.js +1 -0
  300. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/roles/{[...slug]-0bdb66265286ab22.js → [...slug]-db05a80d18c168e5.js} +1 -1
  301. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{roles-e04e18fc295ca76a.js → roles-f55c77e4f46c8d33.js} +1 -1
  302. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-2a1f8737561fdd94.js +1 -0
  303. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users/{[...slug]-0267358c91122109.js → [...slug]-e3bf6e5d8bb250c4.js} +1 -1
  304. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{users-50fed18bb9b8d142.js → users-20f0a050a42a015d.js} +1 -1
  305. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{settings-56f83205752b1323.js → settings-0f0121db7f5ff93d.js} +1 -1
  306. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-99e2748e3c1d57a3.js +1 -0
  307. mage_ai/server/{frontend_dist/_next/static/chunks/pages/templates/[...slug]-9370551ffa462144.js → frontend_dist_base_path_template/_next/static/chunks/pages/templates/[...slug]-f44ccd1499ffd23a.js} +1 -1
  308. mage_ai/server/{frontend_dist/_next/static/chunks/pages/templates-3cff90df13a1a755.js → frontend_dist_base_path_template/_next/static/chunks/pages/templates-1bfaa1c50e844813.js} +1 -1
  309. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/terminal-ed121e305169cf1c.js +1 -0
  310. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/test-9ae68758102cc843.js +1 -0
  311. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{triggers-ffaab4c013e62ba1.js → triggers-572d82d6eb7a5d43.js} +1 -1
  312. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-2d26d80370a2e481.js +1 -0
  313. mage_ai/server/frontend_dist_base_path_template/_next/static/uPDjJYpJMst1q6psbRyte/_buildManifest.js +1 -0
  314. mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
  315. mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
  316. mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
  317. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
  318. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
  319. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +24 -0
  320. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +24 -0
  321. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  322. mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
  323. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
  324. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
  325. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
  326. mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
  327. mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
  328. mage_ai/server/frontend_dist_base_path_template/oauth.html +3 -3
  329. mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
  330. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
  331. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  332. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
  333. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
  334. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  335. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
  336. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  337. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  338. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
  339. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
  340. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
  341. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
  342. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
  343. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  344. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
  345. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  346. mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
  347. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
  348. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
  349. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
  350. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
  351. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
  352. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
  353. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
  354. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
  355. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
  356. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  357. mage_ai/server/frontend_dist_base_path_template/sign-in.html +9 -9
  358. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
  359. mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
  360. mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
  361. mage_ai/server/frontend_dist_base_path_template/test.html +14 -14
  362. mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
  363. mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
  364. mage_ai/server/server.py +43 -15
  365. mage_ai/server/utils/output_display.py +6 -0
  366. mage_ai/server/websocket_server.py +14 -0
  367. mage_ai/services/aws/ecs/config.py +11 -8
  368. mage_ai/services/aws/emr/config.py +1 -0
  369. mage_ai/services/aws/emr/constants.py +1 -0
  370. mage_ai/services/aws/emr/emr.py +20 -7
  371. mage_ai/services/compute/__init__.py +0 -0
  372. mage_ai/services/compute/aws/__init__.py +0 -0
  373. mage_ai/services/compute/aws/constants.py +21 -0
  374. mage_ai/services/compute/aws/models.py +459 -0
  375. mage_ai/services/compute/aws/steps.py +482 -0
  376. mage_ai/services/compute/constants.py +27 -0
  377. mage_ai/services/compute/models.py +212 -0
  378. mage_ai/services/k8s/job_manager.py +3 -0
  379. mage_ai/services/spark/api/aws_emr.py +38 -0
  380. mage_ai/services/spark/api/base.py +7 -4
  381. mage_ai/services/spark/api/constants.py +4 -0
  382. mage_ai/services/spark/api/local.py +25 -24
  383. mage_ai/services/spark/api/service.py +15 -5
  384. mage_ai/services/spark/constants.py +1 -1
  385. mage_ai/services/spark/models/applications.py +45 -3
  386. mage_ai/services/spark/models/base.py +3 -19
  387. mage_ai/services/spark/models/environments.py +16 -11
  388. mage_ai/services/spark/models/executors.py +2 -2
  389. mage_ai/services/spark/models/sqls.py +46 -15
  390. mage_ai/services/spark/models/stages.py +55 -32
  391. mage_ai/services/spark/models/threads.py +2 -2
  392. mage_ai/services/spark/utils.py +22 -6
  393. mage_ai/services/ssh/__init__.py +0 -0
  394. mage_ai/services/ssh/aws/__init__.py +0 -0
  395. mage_ai/services/ssh/aws/emr/__init__.py +0 -0
  396. mage_ai/services/ssh/aws/emr/constants.py +10 -0
  397. mage_ai/services/ssh/aws/emr/models.py +326 -0
  398. mage_ai/services/ssh/aws/emr/utils.py +151 -0
  399. mage_ai/settings/__init__.py +16 -1
  400. mage_ai/settings/secret_generation.py +7 -0
  401. mage_ai/settings/sso.py +20 -0
  402. mage_ai/shared/hash.py +17 -1
  403. mage_ai/shared/models.py +253 -0
  404. mage_ai/streaming/constants.py +2 -0
  405. mage_ai/streaming/sources/activemq.py +89 -0
  406. mage_ai/streaming/sources/nats_js.py +182 -0
  407. mage_ai/streaming/sources/source_factory.py +8 -0
  408. mage_ai/tests/ai/test_ai_functions.py +53 -8
  409. mage_ai/tests/api/endpoints/test_oauths.py +33 -0
  410. mage_ai/tests/api/endpoints/test_projects.py +1 -0
  411. mage_ai/tests/api/endpoints/test_workspaces.py +55 -0
  412. mage_ai/tests/api/operations/test_base.py +7 -5
  413. mage_ai/tests/api/operations/test_operations.py +0 -1
  414. mage_ai/tests/api/operations/test_operations_with_hooks.py +577 -0
  415. mage_ai/tests/api/operations/test_syncs.py +0 -1
  416. mage_ai/tests/api/operations/test_users.py +13 -2
  417. mage_ai/tests/data_preparation/executors/test_block_executor.py +1 -0
  418. mage_ai/tests/data_preparation/models/global_hooks/__init__.py +0 -0
  419. mage_ai/tests/data_preparation/models/global_hooks/test_global_hooks.py +575 -0
  420. mage_ai/tests/data_preparation/models/global_hooks/test_hook.py +760 -0
  421. mage_ai/tests/data_preparation/models/global_hooks/test_utils.py +33 -0
  422. mage_ai/tests/data_preparation/models/test_pipeline.py +5 -0
  423. mage_ai/tests/data_preparation/test_repo_manager.py +11 -0
  424. mage_ai/tests/data_preparation/test_templates.py +1 -0
  425. mage_ai/tests/factory.py +132 -10
  426. mage_ai/tests/orchestration/queue/test_process_queue.py +15 -2
  427. mage_ai/tests/orchestration/test_pipeline_scheduler.py +447 -79
  428. mage_ai/tests/services/aws/ecs/__init__.py +0 -0
  429. mage_ai/tests/services/aws/ecs/test_config.py +144 -0
  430. mage_ai/tests/services/k8s/test_job_manager.py +22 -1
  431. mage_ai/tests/shared/mixins.py +291 -0
  432. mage_ai/tests/shared/test_hash.py +17 -1
  433. mage_ai/tests/streaming/sources/test_activemq.py +32 -0
  434. mage_ai/tests/streaming/sources/test_nats_js.py +32 -0
  435. mage_ai/tests/streaming/sources/test_source_factory.py +26 -1
  436. {mage_ai-0.9.44.dist-info → mage_ai-0.9.46.dist-info}/METADATA +28 -66
  437. {mage_ai-0.9.44.dist-info → mage_ai-0.9.46.dist-info}/RECORD +443 -364
  438. mage_ai/authentication/oauth/active_directory.py +0 -17
  439. mage_ai/server/frontend_dist/_next/static/RPXiX8RpZ7oO-yeaEtV2c/_buildManifest.js +0 -1
  440. mage_ai/server/frontend_dist/_next/static/chunks/1125-91d3ce33140ef041.js +0 -1
  441. mage_ai/server/frontend_dist/_next/static/chunks/1749-607014ecf28268bf.js +0 -1
  442. mage_ai/server/frontend_dist/_next/static/chunks/1952-573c7fc7ad84da6e.js +0 -1
  443. mage_ai/server/frontend_dist/_next/static/chunks/3004-231cad9039ae5dcb.js +0 -1
  444. mage_ai/server/frontend_dist/_next/static/chunks/3419-0873e170ef7d6303.js +0 -1
  445. mage_ai/server/frontend_dist/_next/static/chunks/3932-0ceca9599d6e6d00.js +0 -1
  446. mage_ai/server/frontend_dist/_next/static/chunks/4267-335766a915ee2fa9.js +0 -1
  447. mage_ai/server/frontend_dist/_next/static/chunks/5457-8be2e0a3fe0ba64b.js +0 -1
  448. mage_ai/server/frontend_dist/_next/static/chunks/5499-bca977f466e259e1.js +0 -1
  449. mage_ai/server/frontend_dist/_next/static/chunks/553-edf533e634e85192.js +0 -1
  450. mage_ai/server/frontend_dist/_next/static/chunks/5810-37c6091b29a1fe53.js +0 -1
  451. mage_ai/server/frontend_dist/_next/static/chunks/600-0733eb84f0a0a9e0.js +0 -1
  452. mage_ai/server/frontend_dist/_next/static/chunks/6333-53b6ebbef95a3691.js +0 -1
  453. mage_ai/server/frontend_dist/_next/static/chunks/722-3fff38a9019369fe.js +0 -1
  454. mage_ai/server/frontend_dist/_next/static/chunks/8224-39a93ee1058b6069.js +0 -1
  455. mage_ai/server/frontend_dist/_next/static/chunks/8264-6ef8fdb195694807.js +0 -1
  456. mage_ai/server/frontend_dist/_next/static/chunks/9264-1b5c4b071ed544c3.js +0 -1
  457. mage_ai/server/frontend_dist/_next/static/chunks/framework-7c365855dab1bf41.js +0 -1
  458. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-a4a660fa14cf05a9.js +0 -1
  459. mage_ai/server/frontend_dist/_next/static/chunks/pages/block-layout-c465c14d48392b11.js +0 -1
  460. mage_ai/server/frontend_dist/_next/static/chunks/pages/compute-b1f8d5a7a9a30f2d.js +0 -1
  461. mage_ai/server/frontend_dist/_next/static/chunks/pages/files-93c094bad0f299fb.js +0 -1
  462. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/files-891e5bd5935f7473.js +0 -1
  463. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/settings-d2e4ee4e68d36807.js +0 -1
  464. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users/new-4a49126fcfe8ced0.js +0 -1
  465. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-5f8c5d0bc6ad1113.js +0 -1
  466. mage_ai/server/frontend_dist/_next/static/chunks/pages/oauth-09467512a85c96ed.js +0 -1
  467. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-31bde04718d0d3a8.js +0 -1
  468. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-96718f95103d7844.js +0 -1
  469. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a9266d353f288e8c.js +0 -1
  470. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-b5c29c852262312e.js +0 -1
  471. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-5d525454ff7aeb3f.js +0 -1
  472. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-883f4ae9a4a264c0.js +0 -1
  473. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-c65be964e6398cb7.js +0 -1
  474. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/monitors-1f5b4a974bd39740.js +0 -1
  475. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-074c32397d341de9.js +0 -1
  476. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/syncs-50f5d8706ed0bc73.js +0 -1
  477. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-e151c1552fcb67bd.js +0 -1
  478. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-cc36f0f8c73fee4b.js +0 -1
  479. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-8336c4326f1e7d96.js +0 -1
  480. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/profile-01dd679e4a21e0d9.js +0 -1
  481. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-4d9051c073a9b2ff.js +0 -1
  482. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-88d41c33b8fcb300.js +0 -1
  483. mage_ai/server/frontend_dist/_next/static/chunks/pages/sign-in-d859e07561eb9010.js +0 -1
  484. mage_ai/server/frontend_dist/_next/static/chunks/pages/terminal-578d862f3e56e6e6.js +0 -1
  485. mage_ai/server/frontend_dist/_next/static/chunks/pages/test-1c0588d685b909b9.js +0 -1
  486. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-e284cf1535d93798.js +0 -1
  487. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1125-91d3ce33140ef041.js +0 -1
  488. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1749-607014ecf28268bf.js +0 -1
  489. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1952-573c7fc7ad84da6e.js +0 -1
  490. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3004-231cad9039ae5dcb.js +0 -1
  491. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3419-0873e170ef7d6303.js +0 -1
  492. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3932-0ceca9599d6e6d00.js +0 -1
  493. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/4267-335766a915ee2fa9.js +0 -1
  494. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5457-8be2e0a3fe0ba64b.js +0 -1
  495. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5499-bca977f466e259e1.js +0 -1
  496. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/553-edf533e634e85192.js +0 -1
  497. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5810-37c6091b29a1fe53.js +0 -1
  498. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/600-0733eb84f0a0a9e0.js +0 -1
  499. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/6333-53b6ebbef95a3691.js +0 -1
  500. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/722-3fff38a9019369fe.js +0 -1
  501. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8224-39a93ee1058b6069.js +0 -1
  502. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/8264-6ef8fdb195694807.js +0 -1
  503. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9264-1b5c4b071ed544c3.js +0 -1
  504. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/framework-7c365855dab1bf41.js +0 -1
  505. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-a4a660fa14cf05a9.js +0 -1
  506. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/block-layout-c465c14d48392b11.js +0 -1
  507. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/compute-b1f8d5a7a9a30f2d.js +0 -1
  508. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/files-93c094bad0f299fb.js +0 -1
  509. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/files-891e5bd5935f7473.js +0 -1
  510. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/settings-d2e4ee4e68d36807.js +0 -1
  511. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users/new-4a49126fcfe8ced0.js +0 -1
  512. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-5f8c5d0bc6ad1113.js +0 -1
  513. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/oauth-09467512a85c96ed.js +0 -1
  514. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-31bde04718d0d3a8.js +0 -1
  515. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-96718f95103d7844.js +0 -1
  516. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a9266d353f288e8c.js +0 -1
  517. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/dashboard-b5c29c852262312e.js +0 -1
  518. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-5d525454ff7aeb3f.js +0 -1
  519. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runs-883f4ae9a4a264c0.js +0 -1
  520. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors/block-runtime-c65be964e6398cb7.js +0 -1
  521. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/monitors-1f5b4a974bd39740.js +0 -1
  522. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-074c32397d341de9.js +0 -1
  523. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/syncs-50f5d8706ed0bc73.js +0 -1
  524. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-e151c1552fcb67bd.js +0 -1
  525. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-cc36f0f8c73fee4b.js +0 -1
  526. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-8336c4326f1e7d96.js +0 -1
  527. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/account/profile-01dd679e4a21e0d9.js +0 -1
  528. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-4d9051c073a9b2ff.js +0 -1
  529. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-88d41c33b8fcb300.js +0 -1
  530. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-d859e07561eb9010.js +0 -1
  531. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/terminal-578d862f3e56e6e6.js +0 -1
  532. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/test-1c0588d685b909b9.js +0 -1
  533. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-e284cf1535d93798.js +0 -1
  534. mage_ai/server/frontend_dist_base_path_template/_next/static/rNR5JgSxO3eA2BWGa_i7U/_buildManifest.js +0 -1
  535. /mage_ai/server/frontend_dist/_next/static/{RPXiX8RpZ7oO-yeaEtV2c → 9jB4XPuz6BzxBcG9VNao5}/_ssgManifest.js +0 -0
  536. /mage_ai/server/frontend_dist_base_path_template/_next/static/{rNR5JgSxO3eA2BWGa_i7U → uPDjJYpJMst1q6psbRyte}/_ssgManifest.js +0 -0
  537. {mage_ai-0.9.44.dist-info → mage_ai-0.9.46.dist-info}/LICENSE +0 -0
  538. {mage_ai-0.9.44.dist-info → mage_ai-0.9.46.dist-info}/WHEEL +0 -0
  539. {mage_ai-0.9.44.dist-info → mage_ai-0.9.46.dist-info}/entry_points.txt +0 -0
  540. {mage_ai-0.9.44.dist-info → mage_ai-0.9.46.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,212 @@
1
+ from abc import abstractmethod
2
+ from dataclasses import dataclass, field
3
+ from enum import Enum
4
+ from typing import Dict, List
5
+
6
+ from mage_ai.data_preparation.models.project import Project
7
+ from mage_ai.services.compute.constants import (
8
+ ComputeConnectionActionUUID,
9
+ ComputeConnectionState,
10
+ ComputeManagementApplicationTab,
11
+ )
12
+ from mage_ai.services.spark.constants import ComputeServiceUUID
13
+ from mage_ai.shared.hash import merge_dict
14
+ from mage_ai.shared.models import BaseDataClass
15
+
16
+
17
+ @dataclass
18
+ class ErrorMessage(BaseDataClass):
19
+ message: str
20
+ variables: Dict = field(default_factory=dict)
21
+
22
+
23
+ @dataclass
24
+ class ConnectionCredential(BaseDataClass):
25
+ uuid: str
26
+ description: str = None
27
+ error: ErrorMessage = None
28
+ name: str = None
29
+ required: bool = False
30
+ valid: bool = False
31
+ value: str = None
32
+
33
+ def __post_init__(self):
34
+ if self.error and isinstance(self.error, dict):
35
+ self.error = ErrorMessage.load(**self.error)
36
+
37
+
38
+ class SetupStepStatus(str, Enum):
39
+ COMPLETED = 'completed'
40
+ ERROR = 'error'
41
+ INCOMPLETE = 'incomplete'
42
+
43
+
44
+ @dataclass
45
+ class SetupStep(BaseDataClass):
46
+ name: str
47
+ uuid: str
48
+ description: str = None
49
+ error: ErrorMessage = None
50
+ group: bool = False
51
+ required: bool = True
52
+ status: SetupStepStatus = None
53
+ steps: List[SetupStepStatus] = field(default_factory=list)
54
+ tab: ComputeManagementApplicationTab = None
55
+
56
+ def __post_init__(self):
57
+ if self.error and isinstance(self.error, dict):
58
+ self.error = ErrorMessage.load(**self.error)
59
+
60
+ if self.status and isinstance(self.status, str):
61
+ self.status = SetupStepStatus(self.status)
62
+
63
+ if self.steps and isinstance(self.steps, list):
64
+ steps = []
65
+
66
+ for step in self.steps:
67
+ if isinstance(step, dict):
68
+ steps.append(SetupStep.load(**step))
69
+ else:
70
+ steps.append(step)
71
+
72
+ self.steps = steps
73
+
74
+ if self.tab and isinstance(self.tab, str):
75
+ self.tab = ComputeManagementApplicationTab(self.tab)
76
+
77
+ def status_calculated(self) -> SetupStepStatus:
78
+ if not hasattr(self, '_status_calculated'):
79
+ self._status_calculated = None
80
+
81
+ if self._status_calculated:
82
+ return self._status_calculated
83
+
84
+ if self.status:
85
+ self._status_calculated = self.status
86
+ return self._status_calculated
87
+
88
+ if self.steps:
89
+ if all([
90
+ not step.required or SetupStepStatus.COMPLETED == step.status_calculated()
91
+ for step in self.steps
92
+ ]):
93
+ self._status_calculated = SetupStepStatus.COMPLETED
94
+ elif any([
95
+ not step.required or SetupStepStatus.ERROR == step.status_calculated()
96
+ for step in self.steps
97
+ ]):
98
+ self._status_calculated = SetupStepStatus.ERROR
99
+ elif any([
100
+ not step.required or SetupStepStatus.INCOMPLETE == step.status_calculated()
101
+ for step in self.steps
102
+ ]):
103
+ self._status_calculated = SetupStepStatus.INCOMPLETE
104
+
105
+ return self._status_calculated
106
+
107
+ def to_dict(self, **kwargs) -> Dict:
108
+ return merge_dict(super().to_dict(), dict(
109
+ status_calculated=self.status_calculated(),
110
+ ))
111
+
112
+
113
+ @dataclass
114
+ class ComputeConnectionAction(BaseDataClass):
115
+ name: str
116
+ uuid: ComputeConnectionActionUUID
117
+ description: str = None
118
+
119
+ def __post_init__(self):
120
+ self.serialize_attribute_enum('uuid', ComputeConnectionActionUUID)
121
+
122
+
123
+ @dataclass
124
+ class ComputeConnection(SetupStep):
125
+ actions: List[ComputeConnectionAction] = field(default_factory=list)
126
+ attributes: Dict = field(default_factory=dict)
127
+ connection: Dict = field(default_factory=dict)
128
+ required: bool = False
129
+ state: ComputeConnectionState = None
130
+ steps: List[SetupStep] = field(default_factory=list)
131
+
132
+ def __post_init__(self):
133
+ super().__post_init__()
134
+ self.serialize_attribute_classes('actions', ComputeConnectionAction)
135
+ self.serialize_attribute_classes('steps', SetupStep)
136
+ self.serialize_attribute_enum('state', ComputeConnectionState)
137
+
138
+
139
+ class ComputeService:
140
+ uuid = ComputeServiceUUID.STANDALONE_CLUSTER
141
+
142
+ def __init__(self, project: Project, with_clusters: bool = False):
143
+ self.project = project
144
+ self.with_clusters = with_clusters
145
+
146
+ @classmethod
147
+ def build(self, project: Project, with_clusters: bool = False):
148
+ service_class = self
149
+
150
+ if project and project.spark_config:
151
+ if project.emr_config:
152
+ from mage_ai.services.compute.aws.models import AWSEMRComputeService
153
+
154
+ service_class = AWSEMRComputeService
155
+
156
+ return service_class(project=project, with_clusters=with_clusters)
157
+
158
+ def to_dict(self, **kwargs) -> Dict:
159
+ result = dict(
160
+ connection_credentials=[m.to_dict() for m in self.connection_credentials()],
161
+ setup_steps=[m.to_dict() for m in self.setup_steps()],
162
+ uuid=self.uuid,
163
+ )
164
+
165
+ if self.with_clusters:
166
+ result['clusters'] = self.clusters_and_metadata()
167
+
168
+ return result
169
+
170
+ @property
171
+ def uuid(self) -> ComputeServiceUUID:
172
+ return self.__class__.uuid
173
+
174
+ @abstractmethod
175
+ def active_cluster(self, **kwargs) -> Dict:
176
+ pass
177
+
178
+ @abstractmethod
179
+ def activate_cluster(self, **kwargs) -> Dict:
180
+ pass
181
+
182
+ @abstractmethod
183
+ def create_cluster(self, **kwargs) -> Dict:
184
+ pass
185
+
186
+ @abstractmethod
187
+ def clusters_and_metadata(self, **kwargs) -> Dict:
188
+ pass
189
+
190
+ @abstractmethod
191
+ def get_cluster_details(self, **kwargs) -> Dict:
192
+ pass
193
+
194
+ @abstractmethod
195
+ def connection_credentials(self) -> List[ConnectionCredential]:
196
+ pass
197
+
198
+ @abstractmethod
199
+ def compute_connections(self) -> List[ComputeConnection]:
200
+ pass
201
+
202
+ @abstractmethod
203
+ def setup_steps(self) -> List[SetupStep]:
204
+ pass
205
+
206
+ @abstractmethod
207
+ def terminate_clusters(self, cluster_ids: List[str]) -> None:
208
+ pass
209
+
210
+ @abstractmethod
211
+ def update_cluster(self, cluster_id: str, payload: Dict) -> Dict:
212
+ pass
@@ -173,6 +173,9 @@ class JobManager():
173
173
  mage_server_container_spec = self.get_mage_server_container()
174
174
  container_spec.env = container_spec.env + \
175
175
  [item for item in mage_server_container_spec.env if item not in container_spec.env]
176
+ container_spec.env_from = (container_spec.env_from or []) + \
177
+ [item for item in (mage_server_container_spec.env_from or [])
178
+ if item not in (container_spec.env_from or [])]
176
179
  container_spec.volume_mounts = container_spec.volume_mounts + \
177
180
  [item for item in mage_server_container_spec.volume_mounts
178
181
  if item not in container_spec.volume_mounts]
@@ -0,0 +1,38 @@
1
+ from mage_ai.services.spark.api.constants import SPARK_UI_HOST, SPARK_UI_PORT_AWS_EMR
2
+ from mage_ai.services.spark.api.local import LocalAPI
3
+ from mage_ai.services.ssh.aws.emr.models import SSHTunnel
4
+
5
+
6
+ class AwsEmrAPI(LocalAPI):
7
+ def __init__(self, **kwargs):
8
+ super().__init__(**kwargs)
9
+
10
+ if not self.application_id:
11
+ applications = self.applications_sync()
12
+ if applications:
13
+ applications = sorted(applications, key=lambda x: x.id, reverse=True)
14
+ application = applications[0]
15
+ self.application_id = application.calculated_id()
16
+
17
+ @property
18
+ def spark_ui_url(self) -> str:
19
+ url = f'http://{SPARK_UI_HOST}:{SPARK_UI_PORT_AWS_EMR}'
20
+
21
+ tunnel = SSHTunnel()
22
+ if tunnel:
23
+ connection_details = tunnel.connection_details()
24
+ host = connection_details.get('host')
25
+ port = connection_details.get('port')
26
+ url = f'http://{host or SPARK_UI_HOST}:{port or SPARK_UI_PORT_AWS_EMR}'
27
+
28
+ if self.application_spark_ui_url:
29
+ url = self.application_spark_ui_url
30
+ elif self.spark_session:
31
+ url = self.spark_session.sparkContext.uiWebUrl
32
+
33
+ return url
34
+
35
+ def ready_for_requests(self, **kwargs) -> bool:
36
+ tunnel = SSHTunnel()
37
+ ready = tunnel and tunnel.is_active()
38
+ return True if ready else False
@@ -60,7 +60,7 @@ class BaseAPI(ABC):
60
60
  if self._application:
61
61
  return self._application
62
62
 
63
- self._application = Application(
63
+ self._application = Application.load(
64
64
  id=self.application_id,
65
65
  spark_ui_url=self.application_spark_ui_url,
66
66
  )
@@ -154,8 +154,11 @@ class BaseAPI(ABC):
154
154
  async def environment(self, application_id: str = None, **kwargs) -> Environment:
155
155
  pass
156
156
 
157
+ def ready_for_requests(self, **kwargs) -> bool:
158
+ return True if self.spark_session else False
159
+
157
160
  async def get(self, path: str, host: str = None, query: Dict = None):
158
- if not self.spark_session:
161
+ if not self.ready_for_requests():
159
162
  return {}
160
163
 
161
164
  url = f'{self.endpoint(host=host)}{path}'
@@ -167,12 +170,12 @@ class BaseAPI(ABC):
167
170
  if response.status_code == 200:
168
171
  return response.json()
169
172
  else:
170
- print(f'[WARNING] {self.__class__.__name__} {url}: {response}')
173
+ print(f'[WARNING] {self.__class__.__name__} async {url}: {response}')
171
174
 
172
175
  return {}
173
176
 
174
177
  def get_sync(self, path: str, host: str = None, query: Dict = None):
175
- if not self.spark_session:
178
+ if not self.ready_for_requests():
176
179
  return {}
177
180
 
178
181
  url = f'{self.endpoint(host=host)}{path}'
@@ -0,0 +1,4 @@
1
+ SPARK_UI_API_VERSION = 'v1'
2
+ SPARK_UI_HOST = 'localhost'
3
+ SPARK_UI_PORT = 4040
4
+ SPARK_UI_PORT_AWS_EMR = 18080
@@ -1,6 +1,11 @@
1
1
  from typing import Dict, List
2
2
 
3
3
  from mage_ai.services.spark.api.base import BaseAPI
4
+ from mage_ai.services.spark.api.constants import (
5
+ SPARK_UI_API_VERSION,
6
+ SPARK_UI_HOST,
7
+ SPARK_UI_PORT,
8
+ )
4
9
  from mage_ai.services.spark.models.applications import Application
5
10
  from mage_ai.services.spark.models.environments import Environment
6
11
  from mage_ai.services.spark.models.executors import Executor
@@ -15,10 +20,6 @@ from mage_ai.services.spark.models.stages import (
15
20
  from mage_ai.services.spark.models.threads import Thread
16
21
  from mage_ai.shared.hash import index_by
17
22
 
18
- API_VERSION = 'v1'
19
- SPARK_UI_HOST = 'localhost'
20
- SPARK_UI_PORT = '4040'
21
-
22
23
 
23
24
  class LocalAPI(BaseAPI):
24
25
  @property
@@ -33,7 +34,7 @@ class LocalAPI(BaseAPI):
33
34
  return url
34
35
 
35
36
  def endpoint(self, host: str = None, **kwargs) -> str:
36
- return f'{host or self.spark_ui_url}/api/{API_VERSION}'
37
+ return f'{host or self.spark_ui_url}/api/{SPARK_UI_API_VERSION}'
37
38
 
38
39
  def applications_sync(self, **kwargs) -> List[Application]:
39
40
  models = self.get_sync('/applications')
@@ -46,10 +47,10 @@ class LocalAPI(BaseAPI):
46
47
  applications_cache = Application.get_applications_from_cache()
47
48
  if applications_cache:
48
49
  for application in applications_cache.values():
49
- if application.id in mapping:
50
+ if application.calculated_id() in mapping:
50
51
  continue
51
52
  applications.append(application)
52
- mapping[application.id] = application
53
+ mapping[application.calculated_id()] = application
53
54
 
54
55
  return applications
55
56
 
@@ -64,11 +65,11 @@ class LocalAPI(BaseAPI):
64
65
  applications = [self.application]
65
66
 
66
67
  for application in applications:
67
- if application.id == application_id:
68
+ if application.calculated_id() == application_id:
68
69
  arr.extend([Job.load(application=application, **model) for model in models])
69
70
  else:
70
71
  jobs = self.get_sync(
71
- f'/applications/{application.id}/jobs',
72
+ f'/applications/{application.calculated_id()}/jobs',
72
73
  host=application.spark_ui_url,
73
74
  )
74
75
  arr.extend([Job.load(application=application, **model) for model in jobs])
@@ -89,7 +90,7 @@ class LocalAPI(BaseAPI):
89
90
  applications = [self.application]
90
91
 
91
92
  for application in applications:
92
- if application.id == application_id:
93
+ if application.calculated_id() == application_id:
93
94
  arr.extend(sorted(
94
95
  [Sql.load(
95
96
  application=application,
@@ -100,7 +101,7 @@ class LocalAPI(BaseAPI):
100
101
  ))
101
102
  else:
102
103
  models2 = self.get_sync(
103
- f'/applications/{application.id}/sql',
104
+ f'/applications/{application.calculated_id()}/sql',
104
105
  host=application.spark_ui_url,
105
106
  query=query,
106
107
  )
@@ -129,14 +130,14 @@ class LocalAPI(BaseAPI):
129
130
  applications = [self.application]
130
131
 
131
132
  for application in applications:
132
- if application.id == application_id:
133
+ if application.calculated_id() == application_id:
133
134
  arr.extend([model_class.load(
134
135
  application=application,
135
136
  **model,
136
137
  ) for model in models])
137
138
  else:
138
139
  models2 = self.get_sync(
139
- f'/applications/{application.id}/stages',
140
+ f'/applications/{application.calculated_id()}/stages',
140
141
  host=application.spark_ui_url,
141
142
  query=query,
142
143
  )
@@ -158,10 +159,10 @@ class LocalAPI(BaseAPI):
158
159
  applications_cache = Application.get_applications_from_cache()
159
160
  if applications_cache:
160
161
  for application in applications_cache.values():
161
- if application.id in mapping:
162
+ if application.calculated_id() in mapping:
162
163
  continue
163
164
  applications.append(application)
164
- mapping[application.id] = application
165
+ mapping[application.calculated_id()] = application
165
166
 
166
167
  return applications
167
168
 
@@ -176,11 +177,11 @@ class LocalAPI(BaseAPI):
176
177
  applications = [self.application]
177
178
 
178
179
  for application in applications:
179
- if application.id == application_id:
180
+ if application.calculated_id() == application_id:
180
181
  arr.extend([Job.load(application=application, **model) for model in models])
181
182
  else:
182
183
  jobs = await self.get(
183
- f'/applications/{application.id}/jobs',
184
+ f'/applications/{application.calculated_id()}/jobs',
184
185
  host=application.spark_ui_url,
185
186
  )
186
187
  arr.extend([Job.load(application=application, **model) for model in jobs])
@@ -200,7 +201,7 @@ class LocalAPI(BaseAPI):
200
201
  host=application_spark_ui_url,
201
202
  )
202
203
  return Job.load(
203
- application=Application(
204
+ application=Application.load(
204
205
  id=application_id,
205
206
  spark_ui_url=application_spark_ui_url,
206
207
  ),
@@ -221,14 +222,14 @@ class LocalAPI(BaseAPI):
221
222
  applications = [self.application]
222
223
 
223
224
  for application in applications:
224
- if application.id == application_id:
225
+ if application.calculated_id() == application_id:
225
226
  arr.extend([model_class.load(
226
227
  application=application,
227
228
  **model,
228
229
  ) for model in models])
229
230
  else:
230
231
  models2 = await self.get(
231
- f'/applications/{application.id}/stages',
232
+ f'/applications/{application.calculated_id()}/stages',
232
233
  host=application.spark_ui_url,
233
234
  query=query,
234
235
  )
@@ -254,7 +255,7 @@ class LocalAPI(BaseAPI):
254
255
  query=query,
255
256
  )
256
257
  return Stage.load(
257
- application=Application(
258
+ application=Application.load(
258
259
  id=application_id,
259
260
  spark_ui_url=application_spark_ui_url,
260
261
  ),
@@ -344,7 +345,7 @@ class LocalAPI(BaseAPI):
344
345
  applications = [self.application]
345
346
 
346
347
  for application in applications:
347
- if application.id == application_id:
348
+ if application.calculated_id() == application_id:
348
349
  arr.extend(sorted(
349
350
  [Sql.load(
350
351
  application=application,
@@ -355,7 +356,7 @@ class LocalAPI(BaseAPI):
355
356
  ))
356
357
  else:
357
358
  models2 = await self.get(
358
- f'/applications/{application.id}/sql',
359
+ f'/applications/{application.calculated_id()}/sql',
359
360
  host=application.spark_ui_url,
360
361
  query=query,
361
362
  )
@@ -383,7 +384,7 @@ class LocalAPI(BaseAPI):
383
384
  host=application_spark_ui_url,
384
385
  )
385
386
  return Sql.load(
386
- application=Application(
387
+ application=Application.load(
387
388
  id=application_id,
388
389
  spark_ui_url=application_spark_ui_url,
389
390
  ),
@@ -1,5 +1,6 @@
1
+ from mage_ai.services.spark.api.base import BaseAPI
1
2
  from mage_ai.services.spark.api.local import LocalAPI
2
- from mage_ai.services.spark.constants import ComputeService
3
+ from mage_ai.services.spark.constants import ComputeServiceUUID
3
4
  from mage_ai.services.spark.utils import get_compute_service
4
5
 
5
6
 
@@ -7,18 +8,27 @@ class API:
7
8
  @classmethod
8
9
  def build(
9
10
  self,
10
- all_applications: bool = False,
11
+ all_applications: bool = True,
11
12
  application_id: str = None,
12
13
  application_spark_ui_url: str = None,
13
14
  repo_config=None,
14
15
  spark_session=None,
15
- ):
16
- compute_service = get_compute_service(repo_config)
16
+ ) -> BaseAPI:
17
+ compute_service = get_compute_service(repo_config, ignore_active_kernel=True)
17
18
 
18
- if ComputeService.STANDALONE_CLUSTER == compute_service:
19
+ if ComputeServiceUUID.STANDALONE_CLUSTER == compute_service:
19
20
  return LocalAPI(
20
21
  all_applications=all_applications,
21
22
  spark_session=spark_session,
22
23
  application_id=application_id,
23
24
  application_spark_ui_url=application_spark_ui_url,
24
25
  )
26
+ elif ComputeServiceUUID.AWS_EMR == compute_service:
27
+ from mage_ai.services.spark.api.aws_emr import AwsEmrAPI
28
+
29
+ return AwsEmrAPI(
30
+ all_applications=all_applications,
31
+ spark_session=spark_session,
32
+ application_id=application_id,
33
+ application_spark_ui_url=application_spark_ui_url,
34
+ )
@@ -3,7 +3,7 @@ from enum import Enum
3
3
  SPARK_DIRECTORY_NAME = '.spark'
4
4
 
5
5
 
6
- class ComputeService(str, Enum):
6
+ class ComputeServiceUUID(str, Enum):
7
7
  AWS_EMR = 'AWS_EMR'
8
8
  STANDALONE_CLUSTER = 'STANDALONE_CLUSTER'
9
9
 
@@ -1,9 +1,13 @@
1
1
  import json
2
2
  import os
3
+ import urllib.parse
3
4
  from dataclasses import dataclass
4
5
  from typing import Dict, List
5
6
 
7
+ from mage_ai.services.spark.constants import ComputeServiceUUID
6
8
  from mage_ai.services.spark.models.base import BaseSparkModel
9
+ from mage_ai.services.spark.utils import get_compute_service
10
+ from mage_ai.shared.hash import merge_dict
7
11
 
8
12
 
9
13
  @dataclass
@@ -24,12 +28,32 @@ class ApplicationAttempt(BaseSparkModel):
24
28
  class Application(BaseSparkModel):
25
29
  id: str # local-1697360611228
26
30
  attempts: List[ApplicationAttempt] = None
31
+ attempts_count: int = None
27
32
  name: str = None # my spark app
28
33
  spark_ui_url: str = None
29
34
 
30
35
  def __post_init__(self):
31
36
  if self.attempts and isinstance(self.attempts, list):
32
- self.attempts = [ApplicationAttempt.load(**m) for m in self.attempts]
37
+ arr = []
38
+ for m in self.attempts:
39
+ if m and isinstance(m, dict):
40
+ arr.append(ApplicationAttempt.load(**m))
41
+ else:
42
+ arr.append(m)
43
+ self.attempts = arr
44
+
45
+ @classmethod
46
+ def load(self, **kwargs):
47
+ payload = kwargs.copy() if kwargs else {}
48
+
49
+ if ComputeServiceUUID.AWS_EMR == get_compute_service(ignore_active_kernel=True):
50
+ if payload.get('id'):
51
+ parts = urllib.parse.unquote(payload.get('id')).split('/')
52
+ if len(parts) >= 2:
53
+ payload['id'] = parts[0]
54
+ payload['attempts_count'] = parts[1]
55
+
56
+ return super().load(**payload)
33
57
 
34
58
  @classmethod
35
59
  def __cache_file_path(self):
@@ -52,7 +76,7 @@ class Application(BaseSparkModel):
52
76
  data.update(json.loads(content) or {})
53
77
 
54
78
  data.update({
55
- application.id: application.to_dict(),
79
+ application.calculated_id(): application.to_dict(),
56
80
  })
57
81
 
58
82
  with open(self.__cache_file_path(), 'w') as f:
@@ -68,6 +92,24 @@ class Application(BaseSparkModel):
68
92
  if content:
69
93
  for application_dict in json.loads(content).values():
70
94
  application = self.load(**application_dict)
71
- data[application.id] = application
95
+ data[application.calculated_id()] = application
72
96
 
73
97
  return data
98
+
99
+ def calculated_id(self) -> str:
100
+ if ComputeServiceUUID.AWS_EMR == get_compute_service(ignore_active_kernel=True):
101
+ count = 1
102
+ if self.attempts:
103
+ count = len(self.attempts)
104
+ elif self.attempts_count is not None:
105
+ count = self.attempts_count
106
+
107
+ return f'{self.id}/{count}'
108
+
109
+ return self.id
110
+
111
+ def to_dict(self, **kwargs) -> Dict:
112
+ return merge_dict(
113
+ super().to_dict(**kwargs),
114
+ dict(calculated_id=self.calculated_id()),
115
+ )
@@ -1,27 +1,14 @@
1
1
  import os
2
- from dataclasses import asdict, dataclass
3
- from typing import Dict
4
-
5
- import inflection
2
+ from dataclasses import dataclass
6
3
 
7
4
  from mage_ai.data_preparation.repo_manager import get_repo_config
8
5
  from mage_ai.services.spark.constants import SPARK_DIRECTORY_NAME
9
6
  from mage_ai.settings.repo import get_repo_path
7
+ from mage_ai.shared.models import BaseDataClass
10
8
 
11
9
 
12
10
  @dataclass
13
- class BaseSparkModel:
14
- @classmethod
15
- def load(self, **kwargs):
16
- return self(**self.load_to_dict(**kwargs))
17
-
18
- @classmethod
19
- def load_to_dict(self, **kwargs) -> Dict:
20
- data = {}
21
- for key, value in kwargs.items():
22
- data[inflection.underscore(key)] = value
23
- return data
24
-
11
+ class BaseSparkModel(BaseDataClass):
25
12
  @classmethod
26
13
  def cache_dir_path(self) -> str:
27
14
  repo_config = get_repo_config(repo_path=get_repo_path())
@@ -30,6 +17,3 @@ class BaseSparkModel:
30
17
  repo_config.variables_dir,
31
18
  SPARK_DIRECTORY_NAME,
32
19
  )
33
-
34
- def to_dict(self) -> Dict:
35
- return asdict(self)