Skip to content

Commit

Permalink
apache#317 Multi-tenant web UI
Browse files Browse the repository at this point in the history
  • Loading branch information
kmalik committed Sep 2, 2015
1 parent 43e6caa commit 89d981c
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 2 deletions.
6 changes: 6 additions & 0 deletions airflow/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class AirflowConfigException(Exception):
'web_server_host': '0.0.0.0',
'web_server_port': '8080',
'authenticate': False,
'filter_by_owner': False,
'demo_mode': False,
'secret_key': 'airflowified',
'expose_config': False,
Expand Down Expand Up @@ -115,6 +116,11 @@ class AirflowConfigException(Exception):
# Expose the configuration file in the web server
expose_config = true
# Set to true to turn on authentication : http://pythonhosted.org/airflow/installation.html#web-authentication
authenticate = False
# Filter the list of dags by owner name (requires authentication to be enabled)
filter_by_owner = False
[smtp]
# If you want airflow to send emails on retries, failure, and you want to
Expand Down
17 changes: 15 additions & 2 deletions airflow/www/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
if AUTHENTICATE is False:
login_required = lambda x: x

FILTER_BY_OWNER = False
if conf.getboolean('webserver', 'FILTER_BY_OWNER'):
# filter_by_owner if authentication is enabled and filter_by_owner is true
FILTER_BY_OWNER = AUTHENTICATE

class VisiblePasswordInput(widgets.PasswordInput):
def __init__(self, hide_value=False):
Expand Down Expand Up @@ -278,7 +282,13 @@ class HomeView(AdminIndexView):
def index(self):
session = Session()
DM = models.DagModel
qry = session.query(DM).filter(~DM.is_subdag, DM.is_active).all()
qry = None
# filter the dags if filter_by_owner and current user is not superuser
do_filter = FILTER_BY_OWNER and (not current_user.is_superuser())
if do_filter:
qry = session.query(DM).filter(~DM.is_subdag, DM.is_active, DM.owners == current_user.username).all()
else:
qry = session.query(DM).filter(~DM.is_subdag, DM.is_active).all()
orm_dags = {dag.dag_id: dag for dag in qry}
import_errors = session.query(models.ImportError).all()
for ie in import_errors:
Expand All @@ -289,7 +299,10 @@ def index(self):
session.commit()
session.close()
dags = dagbag.dags.values()
dags = {dag.dag_id: dag for dag in dags if not dag.parent_dag}
if do_filter:
dags = {dag.dag_id: dag for dag in dags if (dag.owner == current_user.username and (not dag.parent_dag))}
else:
dags = {dag.dag_id: dag for dag in dags if not dag.parent_dag}
all_dag_ids = sorted(set(orm_dags.keys()) | set(dags.keys()))
return self.render(
'airflow/dags.html',
Expand Down
12 changes: 12 additions & 0 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,15 @@ exposes a set of hooks in the ``airflow.default_login`` module. You can
alter the content of this module by overriding it as a ``airflow_login``
module. To do this, you would typically copy/paste ``airflow.default_login``
in a ``airflow_login.py`` and put it directly in your ``PYTHONPATH``.
You also need to set webserver.authenticate as true in your ``airflow.cfg``


Multi-tenancy
'''''''''''''

You can filter the list of dags in webserver by owner name, when authentication
is turned on, by setting webserver.filter_by_owner as true in your ``airflow.cfg``
With this, when a user authenticates and logs into webserver, it will see only the dags
which it is owner of. A super_user, will be able to see all the dags although.
This makes the web UI a multi-tenant UI, where a user will only be able to see dags
created by itself.

0 comments on commit 89d981c

Please sign in to comment.