Skip to content

Commit

Permalink
Cleanup and do housekeeping with plugin examples (#28537)
Browse files Browse the repository at this point in the history
This PR performs housekeeping of the plugin examples:

* makes the examples independent of Hive being installed
* adds "has_access" in the examples
* removes the misleading "metastore" (which is hive metastore not
  Airflow Metastore as used in other places

This way our example will be much easier to apply by anyone.
  • Loading branch information
potiuk authored Dec 22, 2022
1 parent 0ebc62f commit 66eb282
Show file tree
Hide file tree
Showing 13 changed files with 109 additions and 530 deletions.
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
!chart
!docs
!licenses
!metastore_browser

# Add those folders to the context so that they are available in the CI container
!scripts/in_container
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
("kubernetes_tests", "/opt/airflow/kubernetes_tests"),
("docker_tests", "/opt/airflow/docker_tests"),
("chart", "/opt/airflow/chart"),
("metastore_browser", "/opt/airflow/metastore_browser"),
]


Expand Down
8 changes: 4 additions & 4 deletions dev/breeze/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,23 @@ def test_visuals():

def test_get_extra_docker_flags_all():
flags = get_extra_docker_flags(MOUNT_ALL)
assert "empty" not in "".join(flags)
assert "/empty," not in "".join(flags)
assert len(flags) < 10


def test_get_extra_docker_flags_selected():
flags = get_extra_docker_flags(MOUNT_SELECTED)
assert "empty" not in "".join(flags)
assert "/empty," not in "".join(flags)
assert len(flags) > 40


def test_get_extra_docker_flags_remove():
flags = get_extra_docker_flags(MOUNT_REMOVE)
assert "empty" in "".join(flags)
assert "/empty," in "".join(flags)
assert len(flags) < 10


def test_get_extra_docker_flags_skip():
flags = get_extra_docker_flags(MOUNT_SKIP)
assert "empty" not in "".join(flags)
assert "/empty," not in "".join(flags)
assert len(flags) < 10
12 changes: 12 additions & 0 deletions docs/apache-airflow/authoring-and-scheduling/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ definitions in Airflow.
# This is the class you derive to create a plugin
from airflow.plugins_manager import AirflowPlugin
from airflow.security import permissions
from airflow.www.auth import has_access
from flask import Blueprint
from flask_appbuilder import expose, BaseView as AppBuilderBaseView
Expand Down Expand Up @@ -201,6 +203,11 @@ definitions in Airflow.
default_view = "test"
@expose("/")
@has_access(
[
(permissions.ACTION_CAN_READ, permissions.RESOURCE_WEBSITE),
]
)
def test(self):
return self.render_template("test_plugin/test.html", content="Hello galaxy!")
Expand All @@ -210,6 +217,11 @@ definitions in Airflow.
default_view = "test"
@expose("/")
@has_access(
[
(permissions.ACTION_CAN_READ, permissions.RESOURCE_WEBSITE),
]
)
def test(self):
return self.render_template("test_plugin/test.html", content="Hello galaxy!")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
under the License.
-->

# Apache Hive metastore plugin
# Apache example plugin

This is an example plugin for Apache Airflow.

This plugin allows you to view Apache Hive metastore from the web UI interface.
This plugin displays empty view.

## Installation

Expand Down
60 changes: 60 additions & 0 deletions docs/apache-airflow/empty_plugin/empty_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Plugins example"""
from __future__ import annotations

from flask import Blueprint
from flask_appbuilder import BaseView, expose

from airflow.plugins_manager import AirflowPlugin
from airflow.security import permissions
from airflow.www.auth import has_access


class EmptyPluginView(BaseView):
"""Creating a Flask-AppBuilder View"""

default_view = "index"

@expose("/")
@has_access(
[
(permissions.ACTION_CAN_READ, permissions.RESOURCE_WEBSITE),
]
)
def index(self):
"""Create default view"""
return self.render_template("empty_plugin/index.html", name="Empty Plugin")


# Creating a flask blueprint
bp = Blueprint(
"Empty Plugin",
__name__,
template_folder="templates",
static_folder="static",
static_url_path="/static/empty_plugin",
)


class EmptyPlugin(AirflowPlugin):
"""Defining the plugin class"""

name = "Empty Plugin"
flask_blueprints = [bp]
appbuilder_views = [{"name": "Empty Plugin", "category": "Extra Views", "view": EmptyPluginView()}]
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,23 @@
under the License.
#}

{% extends 'metastore_browser/base.html' %}
{% extends base_template %}

{% block plugin_content %}
<h4>
<span>Hive Databases</span>
</h4>
{{ table }}
{% block head %}
{{ super() }}
{% endblock %}

{% block body %}
<div>
<h3 style="float: left">
{% block page_header %}{{ name }}{% endblock%}
</h3>
<div id="object" class="select2-drop-mask" style="margin-top: 25px; width: 400px;float: right"></div>
<div style="clear: both"></div>
</div>
{% block plugin_content %}{% endblock %}
{% endblock %}

{% block tail %}
{{ super() }}
{% endblock %}
72 changes: 13 additions & 59 deletions docs/apache-airflow/howto/custom-view-plugin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,22 @@
under the License.
Customize view of Apache Hive Metastore from Airflow web UI
===========================================================
Customize view of Apache from Airflow web UI
============================================

Airflow has feature that allows to integrate a custom UI along with its
core UI using the Plugin manager

This is an example plugin for Airflow that allows to create custom view of
Apache Hive metastore from the web UI of Airflow. Showing Metastore information
like list of the tables in database, finding the table object/ ddl information
for given table, retrieving partition information, retrieving data from the table,
retrieving table objects from Hive Metastore are some of the custom views shown
in this example.
This is an example plugin for Airflow that displays absolutely nothing.

In this plugin, two object reference are derived from the base class
``airflow.plugins_manager.AirflowPlugin``. They are flask_blueprints and
appbuilder_views

Using flask_blueprints in Airflow plugin, the core application can be extended
to support the application that is customized to view Apache Hive Metastore.
to support the application that is customized to view Empty Plugin.
In this object reference, the list of Blueprint object with the static template for
rendering the Metastore information is passed on.
rendering the information.

Using appbuilder_views in Airflow plugin, a class that represents a concept is
added and presented with views and methods to implement it.
Expand All @@ -48,73 +43,32 @@ Custom view Registration
------------------------

A custom view with object reference to flask_appbuilder and Blueprint from flask
and be registered as a part of a :doc:`plugin </authoring-and-scheduling/plugins>`. The following is a
skeleton for us to implement a new custom view:
and be registered as a part of a :doc:`plugin </authoring-and-scheduling/plugins>`.

.. code-block:: python
from airflow.plugins_manager import AirflowPlugin
from flask import Blueprint
from flask_appbuilder import BaseView
class MetastoreBrowserView(BaseView):
pass
# Creating a flask blueprint to integrate the templates and static folder
bp = Blueprint(
"metastore_browser",
__name__,
template_folder="templates",
static_folder="static",
static_url_path="/static/metastore_browser",
)
The following is a skeleton for us to implement a new custom view:

.. exampleinclude:: ../empty_plugin/empty_plugin.py
:language: python

class MetastoreBrowserPlugin(AirflowPlugin):
name = "metastore_browser"
flask_blueprints = [bp]
appbuilder_views = [
{
"category": "Plugins", # name of the tab in Airflow UI
"name": "Hive Metadata Browser", # name of link under the tab
"view": MetastoreBrowserView(),
}
]

``Plugins`` specified in the ``category`` key of ``appbuilder_views`` dictionary is
the name of the tab in the navigation bar of the Airflow UI. ``Hive Metastore Browser``
the name of the tab in the navigation bar of the Airflow UI. ``Empty Plugin``
is the name of the link under the tab ``Plugins``, which will launch the plugin

We have to add Blueprint for generating the part of the application
that needs to be rendered in Airflow web UI. We can define templates, static files
and this blueprint will be registered as part of the Airflow application when the
plugin gets loaded.

Next, we can add code into ``MetastoreBrowserView`` with views and implementing
methods for each of those views. After the implementation, the custom view
created becomes part of the Airflow web UI.

For reference, here's the plugin code within ``MetastoreBrowserView`` class that shows list of tables in the database:

.. exampleinclude:: ../../../metastore_browser/hive_metastore.py
:language: python
:start-after: [START howto_customview_show_database_table]
:end-before: [END howto_customview_show_database_table]

The ``$AIRFLOW_HOME/plugins`` folder with custom view UI have the following folder structure.

::

plugins
├── hive_metastore.py
├── empty_plugin.py
├── templates
| └── metastore_browser
| ├── base.html
| ├── db.html
| ├── dbs.html
│ └── table.html
| └── empty_plugin
| ├── index.html
└── README.md

The HTML files required to render the views built is added as part of the
Expand Down
Loading

0 comments on commit 66eb282

Please sign in to comment.