apache-airflow-providers-fab 3.1.0rc1__py3-none-any.whl → 3.2.0rc1__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.
- airflow/providers/fab/__init__.py +1 -1
- airflow/providers/fab/auth_manager/api_endpoints/user_endpoint.py +3 -1
- airflow/providers/fab/auth_manager/api_fastapi/datamodels/roles.py +13 -7
- airflow/providers/fab/auth_manager/api_fastapi/datamodels/users.py +68 -0
- airflow/providers/fab/auth_manager/api_fastapi/openapi/v2-fab-auth-manager-generated.yaml +485 -18
- airflow/providers/fab/auth_manager/api_fastapi/routes/login.py +2 -4
- airflow/providers/fab/auth_manager/api_fastapi/routes/users.py +133 -0
- airflow/providers/fab/auth_manager/api_fastapi/services/login.py +1 -2
- airflow/providers/fab/auth_manager/api_fastapi/services/users.py +219 -0
- airflow/providers/fab/auth_manager/cli_commands/db_command.py +2 -2
- airflow/providers/fab/auth_manager/cli_commands/permissions_command.py +6 -2
- airflow/providers/fab/auth_manager/cli_commands/user_command.py +3 -3
- airflow/providers/fab/auth_manager/fab_auth_manager.py +18 -51
- airflow/providers/fab/auth_manager/models/__init__.py +6 -6
- airflow/providers/fab/auth_manager/security_manager/override.py +97 -84
- airflow/providers/fab/auth_manager/views/user.py +12 -0
- airflow/providers/fab/cli/__init__.py +18 -0
- airflow/providers/fab/{auth_manager/cli_commands → cli}/definition.py +50 -2
- airflow/providers/fab/get_provider_info.py +8 -0
- airflow/providers/fab/version_compat.py +1 -0
- airflow/providers/fab/www/app.py +2 -7
- airflow/providers/fab/www/extensions/init_appbuilder.py +3 -2
- airflow/providers/fab/www/extensions/init_views.py +11 -7
- airflow/providers/fab/www/package-lock.json +764 -572
- airflow/providers/fab/www/package.json +12 -9
- airflow/providers/fab/www/static/dist/{743.0c0bf201ae17e66a9a3f.js → 743.8fb7d21632ed892227fe.js} +2 -2
- airflow/providers/fab/www/static/dist/{airflowDefaultTheme.ef6fc04c9b6920cd75c9.js → airflowDefaultTheme.51e5d14856ee1ebc83ca.js} +1 -1
- airflow/providers/fab/www/static/dist/{flash.eaaf777ec1b3628cf7be.js → flash.865b6940c00b2a9041b3.js} +1 -1
- airflow/providers/fab/www/static/dist/{loadingDots.76f4332c0a932c3dc08f.js → loadingDots.07f5b9805847242736e1.js} +1 -1
- airflow/providers/fab/www/static/dist/main.8cffe40bcf7cca998f4e.js +2 -0
- airflow/providers/fab/www/static/dist/manifest.json +13 -13
- airflow/providers/fab/www/static/dist/{materialIcons.ad07a489b2f0fc1a96bf.js → materialIcons.4fe84ae36604d84dec78.js} +1 -1
- airflow/providers/fab/www/static/dist/moment.0ec3ee3fb60dc999b1fd.js +1 -0
- airflow/providers/fab/www/static/js/main.js +11 -0
- airflow/providers/fab/www/templates/airflow/main.html +1 -0
- {apache_airflow_providers_fab-3.1.0rc1.dist-info → apache_airflow_providers_fab-3.2.0rc1.dist-info}/METADATA +10 -10
- {apache_airflow_providers_fab-3.1.0rc1.dist-info → apache_airflow_providers_fab-3.2.0rc1.dist-info}/RECORD +50 -46
- {apache_airflow_providers_fab-3.1.0rc1.dist-info → apache_airflow_providers_fab-3.2.0rc1.dist-info}/licenses/3rd-party-licenses/LICENSES-ui.txt +1 -1
- {apache_airflow_providers_fab-3.1.0rc1.dist-info → apache_airflow_providers_fab-3.2.0rc1.dist-info}/licenses/NOTICE +1 -1
- airflow/providers/fab/www/static/dist/main.bc1f701c3d133e2a3bab.js +0 -2
- airflow/providers/fab/www/static/dist/moment.5b85b4f6be2fe9c405ac.js +0 -1
- /airflow/providers/fab/www/static/dist/{743.0c0bf201ae17e66a9a3f.js.LICENSE.txt → 743.8fb7d21632ed892227fe.js.LICENSE.txt} +0 -0
- /airflow/providers/fab/www/static/dist/{airflowDefaultTheme.ef6fc04c9b6920cd75c9.css → airflowDefaultTheme.51e5d14856ee1ebc83ca.css} +0 -0
- /airflow/providers/fab/www/static/dist/{flash.eaaf777ec1b3628cf7be.css → flash.865b6940c00b2a9041b3.css} +0 -0
- /airflow/providers/fab/www/static/dist/{loadingDots.76f4332c0a932c3dc08f.css → loadingDots.07f5b9805847242736e1.css} +0 -0
- /airflow/providers/fab/www/static/dist/{main.bc1f701c3d133e2a3bab.css → main.8cffe40bcf7cca998f4e.css} +0 -0
- /airflow/providers/fab/www/static/dist/{main.bc1f701c3d133e2a3bab.js.LICENSE.txt → main.8cffe40bcf7cca998f4e.js.LICENSE.txt} +0 -0
- /airflow/providers/fab/www/static/dist/{materialIcons.ad07a489b2f0fc1a96bf.css → materialIcons.4fe84ae36604d84dec78.css} +0 -0
- /airflow/providers/fab/www/static/dist/{runtime.254c277d91ce3ac79c64.js → runtime.45b36fb8335446865b53.js} +0 -0
- {apache_airflow_providers_fab-3.1.0rc1.dist-info → apache_airflow_providers_fab-3.2.0rc1.dist-info}/WHEEL +0 -0
- {apache_airflow_providers_fab-3.1.0rc1.dist-info → apache_airflow_providers_fab-3.2.0rc1.dist-info}/entry_points.txt +0 -0
- {apache_airflow_providers_fab-3.1.0rc1.dist-info → apache_airflow_providers_fab-3.2.0rc1.dist-info}/licenses/LICENSE +0 -0
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
19
|
import textwrap
|
|
20
|
+
from typing import TYPE_CHECKING
|
|
20
21
|
|
|
21
22
|
from airflow.cli.cli_config import (
|
|
22
23
|
ARG_DB_FROM_REVISION,
|
|
@@ -35,6 +36,9 @@ from airflow.cli.cli_config import (
|
|
|
35
36
|
lazy_load_command,
|
|
36
37
|
)
|
|
37
38
|
|
|
39
|
+
if TYPE_CHECKING:
|
|
40
|
+
import argparse
|
|
41
|
+
|
|
38
42
|
############
|
|
39
43
|
# # ARGS # #
|
|
40
44
|
############
|
|
@@ -143,7 +147,7 @@ USERS_COMMANDS = (
|
|
|
143
147
|
),
|
|
144
148
|
epilog=(
|
|
145
149
|
"examples:\n"
|
|
146
|
-
'To create
|
|
150
|
+
'To create a user with "Admin" role and username equals to "admin", run:\n'
|
|
147
151
|
"\n"
|
|
148
152
|
" $ airflow users create \\\n"
|
|
149
153
|
" --username admin \\\n"
|
|
@@ -168,7 +172,7 @@ USERS_COMMANDS = (
|
|
|
168
172
|
),
|
|
169
173
|
epilog=(
|
|
170
174
|
"examples:\n"
|
|
171
|
-
'To reset
|
|
175
|
+
'To reset a user with username equals to "admin", run:\n'
|
|
172
176
|
"\n"
|
|
173
177
|
" $ airflow users reset-password \\\n"
|
|
174
178
|
" --username admin"
|
|
@@ -336,3 +340,47 @@ DB_COMMANDS = (
|
|
|
336
340
|
args=(ARG_YES, ARG_DB_SKIP_INIT, ARG_VERBOSE),
|
|
337
341
|
),
|
|
338
342
|
)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def get_fab_cli_commands():
|
|
346
|
+
"""Return CLI commands for FAB auth manager."""
|
|
347
|
+
import packaging.version
|
|
348
|
+
|
|
349
|
+
from airflow import __version__ as airflow_version
|
|
350
|
+
from airflow.cli.cli_config import GroupCommand
|
|
351
|
+
|
|
352
|
+
commands = [
|
|
353
|
+
GroupCommand(
|
|
354
|
+
name="users",
|
|
355
|
+
help="Manage users",
|
|
356
|
+
subcommands=USERS_COMMANDS,
|
|
357
|
+
),
|
|
358
|
+
GroupCommand(
|
|
359
|
+
name="roles",
|
|
360
|
+
help="Manage roles",
|
|
361
|
+
subcommands=ROLES_COMMANDS,
|
|
362
|
+
),
|
|
363
|
+
SYNC_PERM_COMMAND, # not in a command group
|
|
364
|
+
PERMISSIONS_CLEANUP_COMMAND, # single command for permissions cleanup
|
|
365
|
+
]
|
|
366
|
+
# If Airflow version is 3.0.0 or higher, add the fab-db command group
|
|
367
|
+
if packaging.version.parse(
|
|
368
|
+
packaging.version.parse(airflow_version).base_version
|
|
369
|
+
) >= packaging.version.parse("3.0.0"):
|
|
370
|
+
commands.append(GroupCommand(name="fab-db", help="Manage FAB", subcommands=DB_COMMANDS))
|
|
371
|
+
return commands
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def get_parser() -> argparse.ArgumentParser:
|
|
375
|
+
"""
|
|
376
|
+
Generate documentation; used by Sphinx argparse.
|
|
377
|
+
|
|
378
|
+
:meta private:
|
|
379
|
+
"""
|
|
380
|
+
from airflow.cli.cli_parser import AirflowHelpFormatter, DefaultHelpParser, _add_command
|
|
381
|
+
|
|
382
|
+
parser = DefaultHelpParser(prog="airflow", formatter_class=AirflowHelpFormatter)
|
|
383
|
+
subparsers = parser.add_subparsers(dest="subcommand", metavar="GROUP_OR_COMMAND")
|
|
384
|
+
for group_command in get_fab_cli_commands():
|
|
385
|
+
_add_command(subparsers, group_command)
|
|
386
|
+
return parser
|
|
@@ -177,8 +177,16 @@ def get_provider_info():
|
|
|
177
177
|
"example": None,
|
|
178
178
|
"default": "1",
|
|
179
179
|
},
|
|
180
|
+
"cache_ttl": {
|
|
181
|
+
"description": "Number of seconds after which the user cache will expire to refetch updated user and\npermissions.\n",
|
|
182
|
+
"version_added": "3.2.0",
|
|
183
|
+
"type": "integer",
|
|
184
|
+
"example": None,
|
|
185
|
+
"default": "30",
|
|
186
|
+
},
|
|
180
187
|
},
|
|
181
188
|
}
|
|
182
189
|
},
|
|
183
190
|
"auth-managers": ["airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager"],
|
|
191
|
+
"cli": ["airflow.providers.fab.cli.definition.get_fab_cli_commands"],
|
|
184
192
|
}
|
|
@@ -34,3 +34,4 @@ def get_base_airflow_version_tuple() -> tuple[int, int, int]:
|
|
|
34
34
|
|
|
35
35
|
AIRFLOW_V_3_1_PLUS = get_base_airflow_version_tuple() >= (3, 1, 0)
|
|
36
36
|
AIRFLOW_V_3_1_1_PLUS = get_base_airflow_version_tuple() >= (3, 1, 1)
|
|
37
|
+
AIRFLOW_V_3_2_PLUS = get_base_airflow_version_tuple() >= (3, 2, 0)
|
airflow/providers/fab/www/app.py
CHANGED
|
@@ -31,7 +31,7 @@ from airflow.api_fastapi.app import get_auth_manager
|
|
|
31
31
|
from airflow.configuration import conf
|
|
32
32
|
from airflow.exceptions import AirflowConfigException
|
|
33
33
|
from airflow.logging_config import configure_logging
|
|
34
|
-
from airflow.providers.fab.www.extensions.init_appbuilder import
|
|
34
|
+
from airflow.providers.fab.www.extensions.init_appbuilder import init_appbuilder
|
|
35
35
|
from airflow.providers.fab.www.extensions.init_jinja_globals import init_jinja_globals
|
|
36
36
|
from airflow.providers.fab.www.extensions.init_manifest_files import configure_manifest_files
|
|
37
37
|
from airflow.providers.fab.www.extensions.init_security import init_api_auth
|
|
@@ -93,12 +93,7 @@ def create_app(enable_plugins: bool):
|
|
|
93
93
|
init_api_auth(flask_app)
|
|
94
94
|
|
|
95
95
|
with flask_app.app_context():
|
|
96
|
-
|
|
97
|
-
app=flask_app,
|
|
98
|
-
session=db.session(),
|
|
99
|
-
base_template="airflow/main.html",
|
|
100
|
-
enable_plugins=enable_plugins,
|
|
101
|
-
)
|
|
96
|
+
init_appbuilder(flask_app, enable_plugins=enable_plugins)
|
|
102
97
|
init_error_handlers(flask_app)
|
|
103
98
|
# In two scenarios a Flask application can be created:
|
|
104
99
|
# - To support Airflow 2 plugins relying on Flask (``enable_plugins`` is True)
|
|
@@ -49,6 +49,7 @@ if TYPE_CHECKING:
|
|
|
49
49
|
from flask_appbuilder import BaseView
|
|
50
50
|
from flask_appbuilder.security.manager import BaseSecurityManager
|
|
51
51
|
from sqlalchemy.orm import Session
|
|
52
|
+
from sqlalchemy.orm.scoping import scoped_session
|
|
52
53
|
|
|
53
54
|
|
|
54
55
|
# This product contains a modified portion of 'Flask App Builder' developed by Daniel Vaz Gaspar.
|
|
@@ -102,7 +103,7 @@ class AirflowAppBuilder:
|
|
|
102
103
|
def __init__(
|
|
103
104
|
self,
|
|
104
105
|
app=None,
|
|
105
|
-
session:
|
|
106
|
+
session: scoped_session | None = None,
|
|
106
107
|
menu=None,
|
|
107
108
|
indexview=None,
|
|
108
109
|
base_template="airflow/main.html",
|
|
@@ -597,7 +598,7 @@ def init_appbuilder(app: Flask, enable_plugins: bool) -> AirflowAppBuilder:
|
|
|
597
598
|
raise RuntimeError("Session not configured. Call configure_orm() first.")
|
|
598
599
|
return AirflowAppBuilder(
|
|
599
600
|
app=app,
|
|
600
|
-
session=settings.Session
|
|
601
|
+
session=settings.Session,
|
|
601
602
|
base_template="airflow/main.html",
|
|
602
603
|
enable_plugins=enable_plugins,
|
|
603
604
|
)
|
|
@@ -26,7 +26,7 @@ from connexion.exceptions import BadRequestProblem, ProblemException
|
|
|
26
26
|
from flask import request
|
|
27
27
|
|
|
28
28
|
from airflow.api_fastapi.app import get_auth_manager
|
|
29
|
-
from airflow.providers.fab.version_compat import AIRFLOW_V_3_1_PLUS
|
|
29
|
+
from airflow.providers.fab.version_compat import AIRFLOW_V_3_1_PLUS, AIRFLOW_V_3_2_PLUS
|
|
30
30
|
from airflow.providers.fab.www.api_connexion.exceptions import common_error_handler
|
|
31
31
|
|
|
32
32
|
if TYPE_CHECKING:
|
|
@@ -102,11 +102,17 @@ def init_plugins(app):
|
|
|
102
102
|
"""Integrate Flask and FAB with plugins."""
|
|
103
103
|
from airflow import plugins_manager
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
if AIRFLOW_V_3_2_PLUS:
|
|
106
|
+
blueprints, appbuilder_views, appbuilder_menu_links = plugins_manager.get_flask_plugins()
|
|
107
|
+
else:
|
|
108
|
+
plugins_manager.initialize_flask_plugins() # type: ignore
|
|
109
|
+
blueprints = plugins_manager.flask_blueprints # type: ignore
|
|
110
|
+
appbuilder_views = plugins_manager.flask_appbuilder_views # type: ignore
|
|
111
|
+
appbuilder_menu_links = plugins_manager.flask_appbuilder_menu_links # type: ignore
|
|
106
112
|
|
|
107
113
|
appbuilder = app.appbuilder
|
|
108
114
|
|
|
109
|
-
for view in
|
|
115
|
+
for view in appbuilder_views:
|
|
110
116
|
name = view.get("name")
|
|
111
117
|
if name:
|
|
112
118
|
filtered_view_kwargs = {k: v for k, v in view.items() if k not in ["view"]}
|
|
@@ -124,13 +130,11 @@ def init_plugins(app):
|
|
|
124
130
|
# Since Airflow 3.1 flask_appbuilder_menu_links are added to the Airflow 3 UI
|
|
125
131
|
# navbar..
|
|
126
132
|
if not AIRFLOW_V_3_1_PLUS:
|
|
127
|
-
for menu_link in sorted(
|
|
128
|
-
plugins_manager.flask_appbuilder_menu_links, key=lambda x: (x.get("category", ""), x["name"])
|
|
129
|
-
):
|
|
133
|
+
for menu_link in sorted(appbuilder_menu_links, key=lambda x: (x.get("category", ""), x["name"])):
|
|
130
134
|
log.debug("Adding menu link %s to %s", menu_link["name"], menu_link["href"])
|
|
131
135
|
appbuilder.add_link(**menu_link)
|
|
132
136
|
|
|
133
|
-
for blue_print in
|
|
137
|
+
for blue_print in blueprints:
|
|
134
138
|
log.debug("Adding blueprint %s:%s", blue_print["name"], blue_print["blueprint"].import_name)
|
|
135
139
|
app.register_blueprint(blue_print["blueprint"])
|
|
136
140
|
|