This is an automated email from the ASF dual-hosted git repository. potiuk pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push: new fca8aa582e Add Multi-Tenant architecture diagram (#37931) fca8aa582e is described below commit fca8aa582e1b27b86fd519e3d66d0100d5fe0dbf Author: Jarek Potiuk <ja...@potiuk.com> AuthorDate: Fri Mar 8 21:29:36 2024 +0100 Add Multi-Tenant architecture diagram (#37931) This image is not yet connected anywhere, I just want to keep it in Airflow while we are discussing "AIP-67 - Multi-tenant Deployment of Airflow components" and while we are iterating it - it will be easy to collaborate on the diagrams. --- ...diagram_multitenant_airflow_architecture.md5sum | 1 + .../diagram_multitenant_airflow_architecture.png | Bin 0 -> 568294 bytes .../diagram_multitenant_airflow_architecture.py | 247 +++++++++++++++++++++ .../img/diagram_multitenant_architecture.md5sum | 1 + docs/diagrams/config_file.png | Bin 0 -> 116921 bytes 5 files changed, 249 insertions(+) diff --git a/docs/apache-airflow/img/diagram_multitenant_airflow_architecture.md5sum b/docs/apache-airflow/img/diagram_multitenant_airflow_architecture.md5sum new file mode 100644 index 0000000000..da3da1c44e --- /dev/null +++ b/docs/apache-airflow/img/diagram_multitenant_airflow_architecture.md5sum @@ -0,0 +1 @@ +f2dfcb3537301f006d2943e8ee9dd2b2 diff --git a/docs/apache-airflow/img/diagram_multitenant_airflow_architecture.png b/docs/apache-airflow/img/diagram_multitenant_airflow_architecture.png new file mode 100644 index 0000000000..d86f132585 Binary files /dev/null and b/docs/apache-airflow/img/diagram_multitenant_airflow_architecture.png differ diff --git a/docs/apache-airflow/img/diagram_multitenant_airflow_architecture.py b/docs/apache-airflow/img/diagram_multitenant_airflow_architecture.py new file mode 100644 index 0000000000..75524bbe91 --- /dev/null +++ b/docs/apache-airflow/img/diagram_multitenant_airflow_architecture.py @@ -0,0 +1,247 @@ +# 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. +from __future__ import annotations + +from pathlib import Path + +from diagrams import Cluster, Diagram, Edge +from diagrams.custom import Custom +from diagrams.onprem.client import User +from diagrams.onprem.identity import Dex +from rich.console import Console + +MY_DIR = Path(__file__).parent +MY_FILENAME = Path(__file__).with_suffix("").name +PYTHON_MULTIPROCESS_LOGO = MY_DIR.parents[1] / "diagrams" / "python_multiprocess_logo.png" +PACKAGES_IMAGE = MY_DIR.parents[1] / "diagrams" / "packages.png" +DATABASE_IMAGE = MY_DIR.parents[1] / "diagrams" / "database.png" +MULTIPLE_FILES_IMAGE = MY_DIR.parents[1] / "diagrams" / "multiple_files.png" +CONFIG_FILE = MY_DIR.parents[1] / "diagrams" / "config_file.png" + +console = Console(width=400, color_system="standard") + +graph_attr = { + "concentrate": "false", + "splines": "line", +} + +edge_attr = { + "minlen": "2", +} + + +def generate_dag_processor_airflow_diagram(): + dag_processor_architecture_image_file = (MY_DIR / MY_FILENAME).with_suffix(".png") + console.print(f"[bright_blue]Generating architecture image {dag_processor_architecture_image_file}") + with Diagram( + name="", + show=False, + direction="LR", + filename=MY_FILENAME, + outformat="png", + graph_attr=graph_attr, + edge_attr=edge_attr, + ): + operations_user_1 = User("Operations User\nTenant 1") + operations_user_2 = User("Operations User\nTenant 2") + organization_admin = User("Organization Admin") + + with Cluster( + "Shared Organization Airflow Deployment", graph_attr={"bgcolor": "lightgrey", "fontsize": "22"} + ): + with Cluster("Scheduling\n\n"): + schedulers = Custom("Scheduler(s)", PYTHON_MULTIPROCESS_LOGO.as_posix()) + + with Cluster("UI"): + webservers = Custom("Webserver(s)", PYTHON_MULTIPROCESS_LOGO.as_posix()) + auth_manager = Custom("Auth\nManager", PYTHON_MULTIPROCESS_LOGO.as_posix()) + + metadata_db = Custom("Metadata DB", DATABASE_IMAGE.as_posix()) + + organization_plugins_and_packages = Custom( + "Shared\nOrganization\nPlugins &\nPackages", PACKAGES_IMAGE.as_posix() + ) + + organization_config_file = Custom("Config\nFile\nShared\nOrganization", CONFIG_FILE.as_posix()) + + organization_deployment_manager = User("Deployment Manager\nOrganization") + external_organization_identity_system = Dex("Organization Identity System") + external_organization_identity_system >> auth_manager + + webservers >> Edge(color="black", style="solid", reverse=True) >> auth_manager + + ( + auth_manager + >> Edge(color="black", style="solid", reverse=True, label="operates\nTenant 1 Only\n\n") + >> operations_user_1 + ) + ( + auth_manager + >> Edge(color="black", style="solid", reverse=True, label="operates\nTenant 2 Only\n\n") + >> operations_user_2 + ) + ( + auth_manager + >> Edge(color="black", style="solid", reverse=True, label="manages\n\n") + >> organization_admin + ) + + deployment_manager_1 = User("Deployment\nManager\nTenant 1") + dag_author_1 = User("DAG Author\nTenant 1") + + with Cluster("Tenant 1 Airflow Deployment", graph_attr={"bgcolor": "#AAAABB", "fontsize": "22"}): + with Cluster("No DB access"): + with Cluster("Execution"): + workers_1 = Custom("Worker(s)", PYTHON_MULTIPROCESS_LOGO.as_posix()) + triggerer_1 = Custom("Triggerer(s)", PYTHON_MULTIPROCESS_LOGO.as_posix()) + with Cluster("Parsing"): + dag_processors_1 = Custom("DAG\nProcessor(s)", PYTHON_MULTIPROCESS_LOGO.as_posix()) + dag_files_1 = Custom("DAGS/Tenant 1", MULTIPLE_FILES_IMAGE.as_posix()) + plugins_and_packages_1 = Custom("Plugins\n& Packages\nTenant 1", PACKAGES_IMAGE.as_posix()) + config_file_1 = Custom("Config\nFile\nTenant 1", CONFIG_FILE.as_posix()) + with Cluster("DB access"): + internal_api_1 = Custom("Internal API\nTenant 1\n", PYTHON_MULTIPROCESS_LOGO.as_posix()) + ( + internal_api_1 + >> Edge(color="red", style="dotted", reverse=True, label="DB Access\n\n\n") + >> metadata_db + ) + + deployment_manager_2 = User("Deployment\nManager\nTenant 2") + dag_author_2 = User("DAG Author\nTenant 2") + + with Cluster("Tenant 2 Airflow Deployment", graph_attr={"fontsize": "22"}): + with Cluster("No DB access"): + with Cluster("Execution"): + workers_2 = Custom("Worker(s)", PYTHON_MULTIPROCESS_LOGO.as_posix()) + triggerer_2 = Custom("Triggerer(s)", PYTHON_MULTIPROCESS_LOGO.as_posix()) + with Cluster("Parsing"): + dag_processors_2 = Custom("DAG\nProcessor(s)", PYTHON_MULTIPROCESS_LOGO.as_posix()) + dag_files_2 = Custom("DAGS/Tenant 2", MULTIPLE_FILES_IMAGE.as_posix()) + plugins_and_packages_2 = Custom("Plugins\n& Packages\nTenant 2", PACKAGES_IMAGE.as_posix()) + config_file_2 = Custom("Config\nFile\nTenant 2", CONFIG_FILE.as_posix()) + with Cluster("DB access"): + internal_api_2 = Custom("Internal API\nTenant 2", PYTHON_MULTIPROCESS_LOGO.as_posix()) + ( + internal_api_2 + >> Edge(color="red", style="dotted", reverse=True, label="DB Access\n\n\n") + >> metadata_db + ) + + dag_author_1 >> Edge(color="brown", style="dashed", reverse=False, label="author\n\n") >> dag_files_1 + ( + deployment_manager_1 + >> Edge(color="blue", style="solid", reverse=False, label="install\n\n") + >> plugins_and_packages_1 + ) + + ( + deployment_manager_1 + >> Edge(color="blue", style="solid", reverse=False, label="configure\n\n") + >> config_file_1 + ) + + dag_author_2 >> Edge(color="brown", style="dashed", reverse=False, label="author\n\n") >> dag_files_2 + ( + deployment_manager_2 + >> Edge(color="blue", style="solid", reverse=False, label="install\n\n") + >> plugins_and_packages_2 + ) + + ( + deployment_manager_2 + >> Edge(color="blue", style="solid", reverse=False, label="configure\n\n") + >> config_file_2 + ) + + ( + organization_deployment_manager + >> Edge(color="blue", style="solid", reverse=False, label="install\n\n") + >> organization_plugins_and_packages + ) + + ( + organization_deployment_manager + >> Edge(color="blue", style="solid", reverse=False, label="configure\n\n") + >> organization_config_file + ) + + plugins_and_packages_1 >> Edge(style="invis") >> workers_1 + plugins_and_packages_1 >> Edge(style="invis") >> dag_processors_1 + plugins_and_packages_1 >> Edge(style="invis") >> triggerer_1 + + plugins_and_packages_2 >> Edge(style="invis") >> workers_2 + plugins_and_packages_2 >> Edge(style="invis") >> dag_processors_2 + plugins_and_packages_2 >> Edge(style="invis") >> triggerer_2 + + organization_plugins_and_packages >> Edge(style="invis") >> schedulers + organization_plugins_and_packages >> Edge(style="invis") >> webservers + + metadata_db >> Edge(color="red", style="dotted", reverse=True, label="DB Access") >> webservers + metadata_db >> Edge(color="red", style="dotted", reverse=True, label="DB Access") >> schedulers + + ( + dag_processors_1 + >> Edge(color="red", style="dotted", reverse=True, label="GRPC\nHTTPS\n\n") + >> internal_api_1 + ) + ( + workers_1 + >> Edge(color="red", style="dotted", reverse=True, label="GRPC\nHTTPS\n\n") + >> internal_api_1 + ) + ( + triggerer_1 + >> Edge(color="red", style="dotted", reverse=True, label="GRPC\nHTTPS\n\n") + >> internal_api_1 + ) + + ( + dag_processors_2 + >> Edge(color="red", style="dotted", reverse=True, label="GRPC\nHTTPS\n\n") + >> internal_api_2 + ) + ( + workers_2 + >> Edge(color="red", style="dotted", reverse=True, label="GRPC\nHTTPS\n\n") + >> internal_api_2 + ) + ( + triggerer_2 + >> Edge(color="red", style="dotted", reverse=True, label="GRPC\nHTTPS\n\n") + >> internal_api_2 + ) + + dag_files_1 >> Edge(color="brown", style="solid", label="sync\n\n") >> workers_1 + dag_files_1 >> Edge(color="brown", style="solid", label="sync\n\n") >> dag_processors_1 + dag_files_1 >> Edge(color="brown", style="solid", label="sync\n\n") >> triggerer_1 + + dag_files_2 >> Edge(color="brown", style="solid", label="sync\n\n") >> workers_2 + dag_files_2 >> Edge(color="brown", style="solid", label="sync\n\n") >> dag_processors_2 + dag_files_2 >> Edge(color="brown", style="solid", label="sync\n\n") >> triggerer_2 + + # This is for better layout. Invisible edges are used to align the nodes better + webservers - Edge(style="invis") - external_organization_identity_system + schedulers - Edge(style="invis") - external_organization_identity_system + internal_api_1 - Edge(style="invis") - organization_deployment_manager + internal_api_2 - Edge(style="invis") - organization_deployment_manager + + console.print(f"[green]Generating architecture image {dag_processor_architecture_image_file}") + + +if __name__ == "__main__": + generate_dag_processor_airflow_diagram() diff --git a/docs/apache-airflow/img/diagram_multitenant_architecture.md5sum b/docs/apache-airflow/img/diagram_multitenant_architecture.md5sum new file mode 100644 index 0000000000..9b9ffcdc2a --- /dev/null +++ b/docs/apache-airflow/img/diagram_multitenant_architecture.md5sum @@ -0,0 +1 @@ +00f67a1e0cd073ba521da168dc80ccaa diff --git a/docs/diagrams/config_file.png b/docs/diagrams/config_file.png new file mode 100644 index 0000000000..0b6b343a2f Binary files /dev/null and b/docs/diagrams/config_file.png differ