mage-ai 0.9.68__py3-none-any.whl → 0.9.69__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.
- mage_ai/api/resources/SeedResource.py +2 -1
- mage_ai/api/resources/SessionResource.py +13 -1
- mage_ai/authentication/permissions/constants.py +2 -0
- mage_ai/authentication/permissions/seed.py +32 -21
- mage_ai/authentication/providers/active_directory.py +4 -3
- mage_ai/authentication/providers/okta.py +22 -83
- mage_ai/data_preparation/executors/streaming_pipeline_executor.py +77 -7
- mage_ai/data_preparation/models/block/__init__.py +7 -3
- mage_ai/data_preparation/models/block/data_integration/mixins.py +16 -5
- mage_ai/data_preparation/models/block/dynamic/child.py +3 -0
- mage_ai/data_preparation/models/block/dynamic/variables.py +2 -2
- mage_ai/data_preparation/models/block/extension/utils.py +1 -0
- mage_ai/data_preparation/models/block/integration/__init__.py +1 -1
- mage_ai/data_preparation/models/block/sql/__init__.py +1 -1
- mage_ai/data_preparation/models/pipeline.py +22 -6
- mage_ai/data_preparation/models/utils.py +6 -0
- mage_ai/data_preparation/models/variable.py +18 -4
- mage_ai/data_preparation/repo_manager.py +3 -2
- mage_ai/data_preparation/shared/utils.py +1 -1
- mage_ai/data_preparation/templates/data_exporters/mysql.py +2 -2
- mage_ai/data_preparation/templates/data_exporters/oracledb.py +27 -0
- mage_ai/data_preparation/templates/repo/metadata.yaml +1 -0
- mage_ai/io/bigquery.py +131 -58
- mage_ai/io/mysql.py +38 -6
- mage_ai/io/snowflake.py +152 -29
- mage_ai/orchestration/db/models/oauth.py +4 -4
- mage_ai/orchestration/db/models/schedules.py +9 -2
- mage_ai/orchestration/job_manager.py +6 -0
- mage_ai/orchestration/pipeline_scheduler_original.py +16 -6
- mage_ai/orchestration/queue/celery_queue.py +8 -1
- mage_ai/orchestration/queue/process_queue.py +67 -4
- mage_ai/orchestration/queue/queue.py +8 -0
- mage_ai/server/constants.py +1 -1
- mage_ai/server/frontend_dist/404.html +2 -2
- mage_ai/server/frontend_dist/_next/static/{i8pymuJDTVHdWjUP1QSh1 → _krrrgup_C-dPOpX36S8I}/_buildManifest.js +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/1557-df144fbd8b2208c3.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/2717-d9200be634dd6766.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/3548-fa0792ddb88f4646.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/5699-6d708c6b2153ea08.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/7361-8a23dd8360593e7a.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-d9c89527266296f7.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/index-4e12783b064c1cfe.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/{pipeline-runs-a66b4c7641ae03eb.js → pipeline-runs-3edc6270c5b0e962.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-cb88fd075a357fcf.js → frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-1bdfda8edc9cf4a8.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-3591d035bb3bb2b8.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{sync-data-79a4cf66a623e667.js → sync-data-8b793b3b696a2cd3.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-86814e581acaf5db.js → users-a4db8710f703c729.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/sign-in-09414a8b66fb6f06.js +1 -0
- mage_ai/server/frontend_dist/block-layout.html +2 -2
- mage_ai/server/frontend_dist/compute.html +2 -2
- mage_ai/server/frontend_dist/files.html +2 -2
- mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-data-products.html +2 -2
- mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-hooks.html +2 -2
- mage_ai/server/frontend_dist/index.html +2 -2
- mage_ai/server/frontend_dist/manage/files.html +2 -2
- mage_ai/server/frontend_dist/manage/settings.html +2 -2
- mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist/manage/users.html +2 -2
- mage_ai/server/frontend_dist/manage.html +2 -2
- mage_ai/server/frontend_dist/oauth.html +2 -2
- mage_ai/server/frontend_dist/overview.html +2 -2
- mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist/pipelines.html +2 -2
- mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
- mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist/settings.html +2 -2
- mage_ai/server/frontend_dist/sign-in.html +2 -2
- mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist/templates.html +2 -2
- mage_ai/server/frontend_dist/terminal.html +2 -2
- mage_ai/server/frontend_dist/test.html +2 -2
- mage_ai/server/frontend_dist/triggers.html +2 -2
- mage_ai/server/frontend_dist/version-control.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/_next/static/{CKCvjsYCf2imD2X8zAOBf → KLL5mirre9d7_ZeEpaw3s}/_buildManifest.js +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-df144fbd8b2208c3.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-d9200be634dd6766.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-fa0792ddb88f4646.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6d708c6b2153ea08.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-8a23dd8360593e7a.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-d9c89527266296f7.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-4e12783b064c1cfe.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{pipeline-runs-a66b4c7641ae03eb.js → pipeline-runs-3edc6270c5b0e962.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-e1dd1ed71d26c10d.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers-cb88fd075a357fcf.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers-1bdfda8edc9cf4a8.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-3591d035bb3bb2b8.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-503049734a8b082f.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-5b26eeda8aed8a7b.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{sync-data-79a4cf66a623e667.js → sync-data-8b793b3b696a2cd3.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{users-86814e581acaf5db.js → users-a4db8710f703c729.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-09414a8b66fb6f06.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/oauth.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/sign-in.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
- mage_ai/server/scheduler_manager.py +7 -0
- mage_ai/server/server.py +12 -5
- mage_ai/server/websocket_server.py +1 -0
- mage_ai/settings/keys/auth.py +2 -0
- mage_ai/settings/server.py +1 -1
- mage_ai/streaming/sources/influxdb.py +2 -0
- mage_ai/streaming/sources/kafka.py +1 -1
- mage_ai/tests/api/endpoints/mixins.py +10 -9
- mage_ai/tests/api/endpoints/test_seeds.py +24 -0
- mage_ai/tests/api/operations/test_sessions.py +53 -2
- mage_ai/tests/authentication/providers/test_okta.py +43 -0
- mage_ai/tests/orchestration/db/models/test_oauth.py +3 -3
- mage_ai/tests/orchestration/queue/test_process_queue.py +1 -0
- mage_ai/tests/server/test_server.py +8 -4
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.69.dist-info}/METADATA +4 -4
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.69.dist-info}/RECORD +203 -200
- mage_ai/server/frontend_dist/_next/static/chunks/1557-01f0843dc6ac4971.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2717-b5f9575799b594d5.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3548-961ff79ca70038c7.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5699-6efc749f2f8ddd20.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/7361-18d9d8be96e1ce97.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-08790743315de36a.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/index-13760bb72d823b69.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-bd0aff5a5ed8888c.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-d1ee961387c58b7f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-ceb06e1616ee9610.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-8ff16ef9566e911a.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/settings-74d76300942dcee8.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-d7a8bc51bb7a1082.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/sign-in-f59d34429fe022ee.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-01f0843dc6ac4971.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-b5f9575799b594d5.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-961ff79ca70038c7.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6efc749f2f8ddd20.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-18d9d8be96e1ce97.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-08790743315de36a.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-13760bb72d823b69.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-bd0aff5a5ed8888c.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-d1ee961387c58b7f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-ceb06e1616ee9610.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-8ff16ef9566e911a.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-74d76300942dcee8.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-d7a8bc51bb7a1082.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-f59d34429fe022ee.js +0 -1
- /mage_ai/server/frontend_dist/_next/static/{i8pymuJDTVHdWjUP1QSh1 → _krrrgup_C-dPOpX36S8I}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{CKCvjsYCf2imD2X8zAOBf → KLL5mirre9d7_ZeEpaw3s}/_ssgManifest.js +0 -0
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.69.dist-info}/LICENSE +0 -0
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.69.dist-info}/WHEEL +0 -0
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.69.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.69.dist-info}/top_level.txt +0 -0
|
@@ -6,6 +6,7 @@ class SeedResource(GenericResource):
|
|
|
6
6
|
@classmethod
|
|
7
7
|
async def create(self, payload, user, **kwargs):
|
|
8
8
|
if payload.get('roles') and payload.get('permissions'):
|
|
9
|
-
|
|
9
|
+
policy_names = payload.get('policy_names')
|
|
10
|
+
await bootstrap_permissions(policy_names=policy_names)
|
|
10
11
|
|
|
11
12
|
return self({}, user, **kwargs)
|
|
@@ -11,9 +11,10 @@ from mage_ai.orchestration.db.models.oauth import Role, User
|
|
|
11
11
|
from mage_ai.settings import (
|
|
12
12
|
AUTHENTICATION_MODE,
|
|
13
13
|
OAUTH_DEFAULT_ACCESS,
|
|
14
|
+
get_bool_value,
|
|
14
15
|
get_settings_value,
|
|
15
16
|
)
|
|
16
|
-
from mage_ai.settings.keys import LDAP_DEFAULT_ACCESS
|
|
17
|
+
from mage_ai.settings.keys import LDAP_DEFAULT_ACCESS, UPDATE_ROLES_ON_LOGIN
|
|
17
18
|
from mage_ai.usage_statistics.logger import UsageStatisticLogger
|
|
18
19
|
|
|
19
20
|
|
|
@@ -29,6 +30,9 @@ class SessionResource(BaseResource):
|
|
|
29
30
|
|
|
30
31
|
oauth_client = kwargs.get('oauth_client')
|
|
31
32
|
|
|
33
|
+
update_roles_on_login = get_bool_value(
|
|
34
|
+
get_settings_value(UPDATE_ROLES_ON_LOGIN, default='False'))
|
|
35
|
+
|
|
32
36
|
# Oauth sign in
|
|
33
37
|
if token and provider:
|
|
34
38
|
roles = []
|
|
@@ -57,6 +61,9 @@ class SessionResource(BaseResource):
|
|
|
57
61
|
email=email,
|
|
58
62
|
roles_new=roles,
|
|
59
63
|
)
|
|
64
|
+
elif update_roles_on_login and roles:
|
|
65
|
+
user.update(roles_new=roles)
|
|
66
|
+
|
|
60
67
|
oauth_token = generate_access_token(user, oauth_client)
|
|
61
68
|
return self(oauth_token, user, **kwargs)
|
|
62
69
|
|
|
@@ -109,6 +116,11 @@ class SessionResource(BaseResource):
|
|
|
109
116
|
roles_new=roles,
|
|
110
117
|
username=email,
|
|
111
118
|
)
|
|
119
|
+
elif update_roles_on_login:
|
|
120
|
+
role_names = conn.get_user_roles(user_attributes)
|
|
121
|
+
if role_names:
|
|
122
|
+
roles = Role.query.filter(Role.name.in_(role_names)).all()
|
|
123
|
+
user.update(roles_new=roles)
|
|
112
124
|
|
|
113
125
|
oauth_token = generate_access_token(user, kwargs['oauth_client'])
|
|
114
126
|
return self(oauth_token, user, **kwargs)
|
|
@@ -27,6 +27,7 @@ class EntityName(str, Enum):
|
|
|
27
27
|
CustomTemplate = 'CustomTemplate'
|
|
28
28
|
DataProvider = 'DataProvider'
|
|
29
29
|
Database = 'Database'
|
|
30
|
+
Download = 'Download'
|
|
30
31
|
EventMatcher = 'EventMatcher'
|
|
31
32
|
EventRule = 'EventRule'
|
|
32
33
|
ExecutionState = 'ExecutionState'
|
|
@@ -68,6 +69,7 @@ class EntityName(str, Enum):
|
|
|
68
69
|
Scheduler = 'Scheduler'
|
|
69
70
|
SearchResult = 'SearchResult'
|
|
70
71
|
Secret = 'Secret'
|
|
72
|
+
Seed = 'Seed'
|
|
71
73
|
Session = 'Session'
|
|
72
74
|
SparkApplication = 'SparkApplication'
|
|
73
75
|
SparkEnvironment = 'SparkEnvironment'
|
|
@@ -171,13 +171,17 @@ async def action_rules(policy_class):
|
|
|
171
171
|
if scope not in operations_mapping:
|
|
172
172
|
operations_mapping[scope] = {}
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
if not isinstance(config2, list):
|
|
175
|
+
config2 = [config2]
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
for c in config2:
|
|
178
|
+
condition = c.get('condition')
|
|
179
|
+
key = await get_key(policy_class, condition)
|
|
180
|
+
|
|
181
|
+
if key not in operations_mapping[scope]:
|
|
182
|
+
operations_mapping[scope][key] = []
|
|
179
183
|
|
|
180
|
-
|
|
184
|
+
operations_mapping[scope][key].append(operation)
|
|
181
185
|
|
|
182
186
|
return operations_mapping
|
|
183
187
|
|
|
@@ -202,34 +206,40 @@ async def attribute_rules(policy_class, rules):
|
|
|
202
206
|
if config2 is None:
|
|
203
207
|
continue
|
|
204
208
|
|
|
205
|
-
|
|
206
|
-
|
|
209
|
+
if not isinstance(config2, list):
|
|
210
|
+
config2 = [config2]
|
|
211
|
+
|
|
212
|
+
for c in config2:
|
|
213
|
+
condition = c.get('condition')
|
|
214
|
+
key = await get_key(policy_class, condition)
|
|
207
215
|
|
|
208
|
-
|
|
209
|
-
|
|
216
|
+
if key not in mapping[scope]:
|
|
217
|
+
mapping[scope][key] = {}
|
|
210
218
|
|
|
211
|
-
|
|
212
|
-
|
|
219
|
+
if operation not in mapping[scope][key]:
|
|
220
|
+
mapping[scope][key][operation] = []
|
|
213
221
|
|
|
214
|
-
|
|
222
|
+
mapping[scope][key][operation].append(attribute)
|
|
215
223
|
|
|
216
224
|
return mapping
|
|
217
225
|
|
|
218
226
|
|
|
219
|
-
async def bootstrap_permissions():
|
|
227
|
+
async def bootstrap_permissions(policy_names: str = None):
|
|
220
228
|
action_rules_mapping = {}
|
|
221
229
|
query_rules_mapping = {}
|
|
222
230
|
read_rules_mapping = {}
|
|
223
231
|
write_rules_mapping = {}
|
|
224
232
|
|
|
225
|
-
policy_names
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
'
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
+
if policy_names is None:
|
|
234
|
+
policy_names = []
|
|
235
|
+
for n in os.listdir(policies.__path__[0]):
|
|
236
|
+
if n.endswith('Policy.py') and n not in [
|
|
237
|
+
'AsyncBasePolicy.py',
|
|
238
|
+
'BasePolicy.py',
|
|
239
|
+
'SeedPolicy.py',
|
|
240
|
+
'UserPolicy.py',
|
|
241
|
+
]:
|
|
242
|
+
policy_names.append(n.replace('Policy.py', ''))
|
|
233
243
|
|
|
234
244
|
for policy_name in policy_names:
|
|
235
245
|
policy_class = getattr(
|
|
@@ -238,6 +248,7 @@ async def bootstrap_permissions():
|
|
|
238
248
|
)
|
|
239
249
|
|
|
240
250
|
model_name = policy_class.model_name()
|
|
251
|
+
print(f'Processing {model_name}...')
|
|
241
252
|
action_rules_mapping[model_name] = await action_rules(policy_class)
|
|
242
253
|
query_rules_mapping[model_name] = await attribute_rules(
|
|
243
254
|
policy_class,
|
|
@@ -34,10 +34,11 @@ class ADProvider(SsoProvider, OauthProvider):
|
|
|
34
34
|
self.client_secret = get_settings_value(ACTIVE_DIRECTORY_CLIENT_SECRET)
|
|
35
35
|
self.__validate()
|
|
36
36
|
|
|
37
|
-
self.roles_mapping =
|
|
38
|
-
|
|
37
|
+
self.roles_mapping = {}
|
|
38
|
+
roles_mapping = get_settings_value(ACTIVE_DIRECTORY_ROLES_MAPPING)
|
|
39
|
+
if roles_mapping:
|
|
39
40
|
try:
|
|
40
|
-
self.roles_mapping = json.loads(
|
|
41
|
+
self.roles_mapping = json.loads(roles_mapping)
|
|
41
42
|
except Exception:
|
|
42
43
|
logger.exception('Failed to parse roles mapping.')
|
|
43
44
|
|
|
@@ -1,104 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
import uuid
|
|
3
|
-
from typing import Awaitable, Dict
|
|
4
|
-
|
|
5
|
-
import aiohttp
|
|
6
|
-
from aiohttp import BasicAuth
|
|
1
|
+
from urllib.parse import unquote, urlparse
|
|
7
2
|
|
|
8
3
|
from mage_ai.authentication.oauth.constants import ProviderName
|
|
9
|
-
from mage_ai.authentication.providers.
|
|
10
|
-
from mage_ai.authentication.providers.sso import SsoProvider
|
|
11
|
-
from mage_ai.authentication.providers.utils import get_base_url
|
|
4
|
+
from mage_ai.authentication.providers.oidc import OidcProvider
|
|
12
5
|
from mage_ai.settings import get_settings_value
|
|
13
6
|
from mage_ai.settings.keys import OKTA_CLIENT_ID, OKTA_CLIENT_SECRET, OKTA_DOMAIN_URL
|
|
14
7
|
|
|
15
8
|
|
|
16
|
-
class OktaProvider(
|
|
9
|
+
class OktaProvider(
|
|
10
|
+
OidcProvider
|
|
11
|
+
): # Okta configuration uses OIDC so we can just subclass the OidcProvider
|
|
17
12
|
provider = ProviderName.OKTA
|
|
18
13
|
|
|
19
14
|
def __init__(self):
|
|
20
15
|
self.hostname = get_settings_value(OKTA_DOMAIN_URL)
|
|
21
16
|
self.client_id = get_settings_value(OKTA_CLIENT_ID)
|
|
22
17
|
self.client_secret = get_settings_value(OKTA_CLIENT_SECRET)
|
|
18
|
+
self.parsed_url = urlparse(unquote(self.hostname))
|
|
19
|
+
if not self.parsed_url.scheme:
|
|
20
|
+
self.parsed_url = urlparse(unquote(f'https://{self.hostname}'))
|
|
23
21
|
self.__validate()
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
self.discovery_url = (
|
|
24
|
+
f'https://{self.parsed_url.netloc}/.well-known/openid-configuration'
|
|
25
|
+
)
|
|
26
|
+
self.discover()
|
|
27
27
|
|
|
28
28
|
def __validate(self):
|
|
29
|
-
if not self.
|
|
30
|
-
raise
|
|
29
|
+
if not self.parsed_url.netloc:
|
|
30
|
+
raise ValueError(
|
|
31
31
|
'Okta hostname is empty. '
|
|
32
|
-
'Make sure the OKTA_DOMAIN_URL environment variable is set.'
|
|
32
|
+
'Make sure the OKTA_DOMAIN_URL environment variable is set.'
|
|
33
|
+
)
|
|
33
34
|
if not self.client_id:
|
|
34
|
-
raise
|
|
35
|
+
raise ValueError(
|
|
35
36
|
'Okta client id is empty. '
|
|
36
|
-
'Make sure the OKTA_CLIENT_ID environment variable is set.'
|
|
37
|
+
'Make sure the OKTA_CLIENT_ID environment variable is set.'
|
|
38
|
+
)
|
|
37
39
|
if not self.client_secret:
|
|
38
|
-
raise
|
|
40
|
+
raise ValueError(
|
|
39
41
|
'Okta client secret is empty. '
|
|
40
|
-
'Make sure the OKTA_CLIENT_SECRET environment variable is set.'
|
|
41
|
-
|
|
42
|
-
def get_auth_url_response(self, redirect_uri: str = None, **kwargs) -> Dict:
|
|
43
|
-
base_url = get_base_url(redirect_uri)
|
|
44
|
-
redirect_uri_query = dict(
|
|
45
|
-
provider=self.provider,
|
|
46
|
-
redirect_uri=redirect_uri,
|
|
47
|
-
)
|
|
48
|
-
query = dict(
|
|
49
|
-
client_id=self.client_id,
|
|
50
|
-
redirect_uri=urllib.parse.quote_plus(
|
|
51
|
-
f'{base_url}/oauth',
|
|
52
|
-
),
|
|
53
|
-
response_mode='query',
|
|
54
|
-
response_type='code',
|
|
55
|
-
scope='openid email profile',
|
|
56
|
-
state=uuid.uuid4().hex,
|
|
57
|
-
)
|
|
58
|
-
query_strings = []
|
|
59
|
-
for k, v in query.items():
|
|
60
|
-
query_strings.append(f'{k}={v}')
|
|
61
|
-
|
|
62
|
-
return dict(
|
|
63
|
-
url=f"{self.hostname}/oauth2/default/v1/authorize?{'&'.join(query_strings)}",
|
|
64
|
-
redirect_query_params=redirect_uri_query,
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
async def get_access_token_response(self, code: str, **kwargs) -> Awaitable[Dict]:
|
|
68
|
-
base_url = get_base_url(kwargs.get('redirect_uri'))
|
|
69
|
-
data = dict()
|
|
70
|
-
async with aiohttp.ClientSession() as session:
|
|
71
|
-
async with session.post(
|
|
72
|
-
f'{self.hostname}/oauth2/default/v1/token',
|
|
73
|
-
headers={
|
|
74
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
75
|
-
},
|
|
76
|
-
data=dict(
|
|
77
|
-
grant_type='authorization_code',
|
|
78
|
-
code=code,
|
|
79
|
-
redirect_uri=f'{base_url}/oauth',
|
|
80
|
-
),
|
|
81
|
-
auth=BasicAuth(self.client_id, self.client_secret),
|
|
82
|
-
timeout=20,
|
|
83
|
-
) as response:
|
|
84
|
-
data = await response.json()
|
|
85
|
-
|
|
86
|
-
return data
|
|
87
|
-
|
|
88
|
-
async def get_user_info(self, access_token: str = None, **kwargs) -> Awaitable[Dict]:
|
|
89
|
-
if access_token is None:
|
|
90
|
-
raise Exception('Access token is required to fetch user info.')
|
|
91
|
-
async with aiohttp.ClientSession() as session:
|
|
92
|
-
async with session.get(
|
|
93
|
-
f'{self.hostname}/oauth2/default/v1/userinfo',
|
|
94
|
-
headers={
|
|
95
|
-
'Authorization': f'Bearer {access_token}'
|
|
96
|
-
},
|
|
97
|
-
timeout=10,
|
|
98
|
-
) as response:
|
|
99
|
-
userinfo_resp = await response.json()
|
|
100
|
-
|
|
101
|
-
return dict(
|
|
102
|
-
email=userinfo_resp.get('email'),
|
|
103
|
-
username=userinfo_resp.get('sub'),
|
|
104
|
-
)
|
|
42
|
+
'Make sure the OKTA_CLIENT_SECRET environment variable is set.'
|
|
43
|
+
)
|
|
@@ -2,9 +2,12 @@ import asyncio
|
|
|
2
2
|
import copy
|
|
3
3
|
import logging
|
|
4
4
|
import os
|
|
5
|
+
import traceback
|
|
5
6
|
from contextlib import redirect_stderr, redirect_stdout
|
|
7
|
+
from datetime import datetime
|
|
6
8
|
from typing import Callable, Dict, List, Union
|
|
7
9
|
|
|
10
|
+
import pytz
|
|
8
11
|
import yaml
|
|
9
12
|
from jinja2 import Template
|
|
10
13
|
|
|
@@ -12,9 +15,14 @@ from mage_ai.data_preparation.executors.pipeline_executor import PipelineExecuto
|
|
|
12
15
|
from mage_ai.data_preparation.logging.logger import DictLogger
|
|
13
16
|
from mage_ai.data_preparation.models.constants import BlockLanguage, BlockType
|
|
14
17
|
from mage_ai.data_preparation.models.pipeline import Pipeline
|
|
18
|
+
from mage_ai.data_preparation.shared.retry import RetryConfig
|
|
15
19
|
from mage_ai.data_preparation.shared.stream import StreamToLogger
|
|
16
20
|
from mage_ai.data_preparation.shared.utils import get_template_vars
|
|
21
|
+
from mage_ai.orchestration.db import safe_db_query
|
|
22
|
+
from mage_ai.orchestration.db.models.schedules import PipelineRun
|
|
17
23
|
from mage_ai.shared.hash import merge_dict
|
|
24
|
+
from mage_ai.shared.retry import retry
|
|
25
|
+
from mage_ai.usage_statistics.logger import UsageStatisticLogger
|
|
18
26
|
|
|
19
27
|
|
|
20
28
|
class StreamingPipelineExecutor(PipelineExecutor):
|
|
@@ -22,6 +30,7 @@ class StreamingPipelineExecutor(PipelineExecutor):
|
|
|
22
30
|
super().__init__(pipeline, **kwargs)
|
|
23
31
|
# TODO: Support custom log destination for streaming pipelines
|
|
24
32
|
self.parse_and_validate_blocks()
|
|
33
|
+
self.retry_metadata = dict(attempts=0)
|
|
25
34
|
|
|
26
35
|
def parse_and_validate_blocks(self):
|
|
27
36
|
"""
|
|
@@ -67,6 +76,8 @@ class StreamingPipelineExecutor(PipelineExecutor):
|
|
|
67
76
|
self,
|
|
68
77
|
build_block_output_stdout: Callable[..., object] = None,
|
|
69
78
|
global_vars: Dict = None,
|
|
79
|
+
pipeline_run_id: int = None,
|
|
80
|
+
retry_config: Dict = None,
|
|
70
81
|
**kwargs,
|
|
71
82
|
) -> None:
|
|
72
83
|
# TODOs:
|
|
@@ -74,6 +85,7 @@ class StreamingPipelineExecutor(PipelineExecutor):
|
|
|
74
85
|
# 2. Support flink pipeline
|
|
75
86
|
|
|
76
87
|
tags = self.build_tags(**kwargs)
|
|
88
|
+
self.logging_tags = tags
|
|
77
89
|
if build_block_output_stdout:
|
|
78
90
|
stdout_logger = logging.getLogger('streaming_pipeline_executor')
|
|
79
91
|
self.logger = DictLogger(stdout_logger)
|
|
@@ -82,24 +94,53 @@ class StreamingPipelineExecutor(PipelineExecutor):
|
|
|
82
94
|
self.logger = DictLogger(self.logger_manager.logger, logging_tags=tags)
|
|
83
95
|
stdout = StreamToLogger(self.logger, logging_tags=tags)
|
|
84
96
|
try:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
if retry_config is None:
|
|
98
|
+
retry_config = self.pipeline.retry_config or dict()
|
|
99
|
+
infinite_retries = False if retry_config else False
|
|
100
|
+
|
|
101
|
+
if type(retry_config) is not RetryConfig:
|
|
102
|
+
retry_config = RetryConfig.load(config=retry_config)
|
|
103
|
+
|
|
104
|
+
@retry(
|
|
105
|
+
retries=retry_config.retries,
|
|
106
|
+
delay=retry_config.delay,
|
|
107
|
+
max_delay=retry_config.max_delay,
|
|
108
|
+
exponential_backoff=retry_config.exponential_backoff,
|
|
109
|
+
logger=self.logger,
|
|
110
|
+
logging_tags=self.logging_tags,
|
|
111
|
+
retry_metadata=self.retry_metadata,
|
|
112
|
+
)
|
|
113
|
+
def __execute_with_retry():
|
|
114
|
+
with redirect_stdout(stdout):
|
|
115
|
+
with redirect_stderr(stdout):
|
|
116
|
+
self.__execute_in_python(
|
|
117
|
+
build_block_output_stdout=build_block_output_stdout,
|
|
118
|
+
global_vars=global_vars,
|
|
119
|
+
pipeline_run_id=pipeline_run_id,
|
|
120
|
+
)
|
|
121
|
+
__execute_with_retry()
|
|
91
122
|
except Exception as e:
|
|
92
123
|
if not build_block_output_stdout:
|
|
93
124
|
self.logger.exception(
|
|
94
125
|
f'Failed to execute streaming pipeline {self.pipeline.uuid}',
|
|
95
126
|
**merge_dict(dict(error=e), tags),
|
|
96
127
|
)
|
|
128
|
+
if not infinite_retries:
|
|
129
|
+
# If pipeline retry config is present, fail the pipeline after the retries
|
|
130
|
+
self.__update_pipeline_run_status(
|
|
131
|
+
pipeline_run_id,
|
|
132
|
+
PipelineRun.PipelineRunStatus.FAILED,
|
|
133
|
+
error=e,
|
|
134
|
+
)
|
|
135
|
+
|
|
97
136
|
raise e
|
|
98
137
|
|
|
99
138
|
def __execute_in_python(
|
|
100
139
|
self,
|
|
101
140
|
build_block_output_stdout: Callable[..., object] = None,
|
|
102
|
-
global_vars: Dict = None
|
|
141
|
+
global_vars: Dict = None,
|
|
142
|
+
pipeline_run_id: int = None,
|
|
143
|
+
|
|
103
144
|
):
|
|
104
145
|
from mage_ai.streaming.sinks.sink_factory import SinkFactory
|
|
105
146
|
from mage_ai.streaming.sources.base import SourceConsumeMethod
|
|
@@ -227,6 +268,35 @@ class StreamingPipelineExecutor(PipelineExecutor):
|
|
|
227
268
|
for sink in sinks_by_uuid.values():
|
|
228
269
|
sink.destroy()
|
|
229
270
|
|
|
271
|
+
@safe_db_query
|
|
272
|
+
def __update_pipeline_run_status(
|
|
273
|
+
self,
|
|
274
|
+
pipeline_run_id: int,
|
|
275
|
+
status: PipelineRun.PipelineRunStatus,
|
|
276
|
+
error: Exception = None,
|
|
277
|
+
):
|
|
278
|
+
if not pipeline_run_id or not status:
|
|
279
|
+
return
|
|
280
|
+
pipeline_run = PipelineRun.query.get(pipeline_run_id)
|
|
281
|
+
pipeline_run.update(
|
|
282
|
+
status=status,
|
|
283
|
+
completed_at=datetime.now(tz=pytz.UTC),
|
|
284
|
+
)
|
|
285
|
+
if status == PipelineRun.PipelineRunStatus.FAILED:
|
|
286
|
+
asyncio.run(UsageStatisticLogger().pipeline_run_ended(pipeline_run))
|
|
287
|
+
error_msg = None
|
|
288
|
+
stacktrace = None
|
|
289
|
+
if error is not None:
|
|
290
|
+
error_msg = str(error)
|
|
291
|
+
stacktrace = traceback.format_exc()
|
|
292
|
+
notification_sender = self.pipeline.get_notification_sender()
|
|
293
|
+
notification_sender.send_pipeline_run_failure_message(
|
|
294
|
+
pipeline=self.pipeline,
|
|
295
|
+
pipeline_run=pipeline_run,
|
|
296
|
+
error=error_msg,
|
|
297
|
+
stacktrace=stacktrace,
|
|
298
|
+
)
|
|
299
|
+
|
|
230
300
|
def __execute_in_flink(self):
|
|
231
301
|
"""
|
|
232
302
|
TODO: Implement this method
|
|
@@ -907,10 +907,11 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
|
|
|
907
907
|
parts = get_path_parts(file_path)
|
|
908
908
|
|
|
909
909
|
if parts and len(parts) >= 3:
|
|
910
|
+
from mage_ai.data_preparation.models.block.block_factory import BlockFactory
|
|
911
|
+
|
|
910
912
|
# If file_path == transformers/test4.py
|
|
911
913
|
# parts ==
|
|
912
914
|
# ('/home/src/default_repo/default_platform2/project3', 'transformers', 'test4.py')
|
|
913
|
-
|
|
914
915
|
# If project platform platform activated, then parts ==
|
|
915
916
|
# ('/home/src', 'default_repo', 'data_loaders/astral_violet.py')
|
|
916
917
|
|
|
@@ -929,7 +930,7 @@ class Block(DataIntegrationMixin, SparkBlock, ProjectPlatformAccessible):
|
|
|
929
930
|
configuration = dict(file_path=file_path, file_source=dict(path=file_path))
|
|
930
931
|
language = FILE_EXTENSION_TO_BLOCK_LANGUAGE.get(extension)
|
|
931
932
|
|
|
932
|
-
return
|
|
933
|
+
return BlockFactory.get_block(
|
|
933
934
|
block_uuid,
|
|
934
935
|
block_uuid,
|
|
935
936
|
block_type,
|
|
@@ -3473,12 +3474,15 @@ df = get_variable('{self.pipeline.uuid}', '{self.uuid}', 'df')
|
|
|
3473
3474
|
|
|
3474
3475
|
cache = BlockCache()
|
|
3475
3476
|
if detach:
|
|
3477
|
+
from mage_ai.data_preparation.models.block.block_factory import (
|
|
3478
|
+
BlockFactory,
|
|
3479
|
+
)
|
|
3476
3480
|
""""
|
|
3477
3481
|
New block added to pipeline, so it must be added to the block cache.
|
|
3478
3482
|
Old block no longer in pipeline, so it must be removed from block cache.
|
|
3479
3483
|
"""
|
|
3480
3484
|
cache.add_pipeline(self, self.pipeline)
|
|
3481
|
-
old_block =
|
|
3485
|
+
old_block = BlockFactory.get_block(
|
|
3482
3486
|
old_uuid,
|
|
3483
3487
|
old_uuid,
|
|
3484
3488
|
self.type,
|
|
@@ -202,18 +202,29 @@ class DataIntegrationMixin:
|
|
|
202
202
|
with open(catalog_full_path, mode='w') as f:
|
|
203
203
|
f.write(json.dumps(catalog))
|
|
204
204
|
|
|
205
|
-
def is_data_integration(self) -> bool:
|
|
205
|
+
def is_data_integration(self, pipeline_project: Project = None) -> bool:
|
|
206
206
|
"""
|
|
207
207
|
Check if the block is a data integration block.
|
|
208
208
|
If the data_integration_in_batch_pipeline feature is not enabled, return False.
|
|
209
209
|
|
|
210
|
+
Args:
|
|
211
|
+
pipeline_project (Project, optional): A cached Project value to avoid
|
|
212
|
+
looking it up many times when called inside loops. Defaults to None.
|
|
213
|
+
|
|
210
214
|
Returns:
|
|
211
215
|
bool: True if it's a data integration block, False otherwise.
|
|
212
216
|
"""
|
|
213
|
-
if not self.pipeline
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
+
if not self.pipeline:
|
|
218
|
+
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
actual_project: Project = pipeline_project
|
|
222
|
+
if not actual_project:
|
|
223
|
+
actual_project = Project(self.pipeline.repo_config)
|
|
224
|
+
|
|
225
|
+
if not actual_project.is_feature_enabled(
|
|
226
|
+
FeatureUUID.DATA_INTEGRATION_IN_BATCH_PIPELINE,
|
|
227
|
+
):
|
|
217
228
|
|
|
218
229
|
return False
|
|
219
230
|
|
|
@@ -6,7 +6,7 @@ from typing import Any, Dict, List, Tuple, Union
|
|
|
6
6
|
|
|
7
7
|
import pandas as pd
|
|
8
8
|
|
|
9
|
-
from mage_ai.data_preparation.models.constants import BlockLanguage
|
|
9
|
+
from mage_ai.data_preparation.models.constants import BlockLanguage, BlockType
|
|
10
10
|
from mage_ai.data_preparation.models.variable import Variable
|
|
11
11
|
from mage_ai.shared.memory import get_memory_usage, get_memory_usage_async
|
|
12
12
|
from mage_ai.shared.strings import to_ordinal_integers
|
|
@@ -470,7 +470,7 @@ def fetch_input_variables_for_dynamic_upstream_blocks(
|
|
|
470
470
|
|
|
471
471
|
# If dynamic child should reduce its output (which means it passes the entire
|
|
472
472
|
# output to its downstream blocks):
|
|
473
|
-
if should_reduce_output(upstream_block):
|
|
473
|
+
if should_reduce_output(upstream_block) and block.type != BlockType.EXTENSION:
|
|
474
474
|
child_data = []
|
|
475
475
|
metadata = {}
|
|
476
476
|
for lazy_variable_set in lazy_variable_controller:
|
|
@@ -155,7 +155,7 @@ class IntegrationBlock(Block):
|
|
|
155
155
|
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
156
156
|
|
|
157
157
|
for line in proc.stdout:
|
|
158
|
-
f.write(line.decode())
|
|
158
|
+
f.write(line.decode())
|
|
159
159
|
print_log_from_line(
|
|
160
160
|
line,
|
|
161
161
|
config=config,
|