| #!/usr/bin/env python3 |
| # 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. |
| # /// script |
| # requires-python = ">=3.10" |
| # dependencies = [ |
| # "rich>=13.6.0", |
| # ] |
| # /// |
| from __future__ import annotations |
| |
| import json |
| from pathlib import Path |
| |
| from rich import print |
| from rich.prompt import Confirm |
| |
| # Debug port mappings for Airflow components |
| DEBUG_PORTS = { |
| "scheduler": 50231, |
| "dag-processor": 50232, |
| "triggerer": 50233, |
| "api-server": 50234, |
| "celery-worker": 50235, |
| "edge-worker": 50236, |
| } |
| |
| # Component descriptions for better naming |
| COMPONENT_NAMES = { |
| "scheduler": "Scheduler", |
| "dag-processor": "DAG Processor", |
| "triggerer": "Triggerer", |
| "api-server": "API Server", |
| "celery-worker": "Celery Worker", |
| "edge-worker": "Edge Worker", |
| } |
| |
| ROOT_AIRFLOW_FOLDER_PATH = Path(__file__).parent |
| VSCODE_FOLDER_PATH = ROOT_AIRFLOW_FOLDER_PATH / ".vscode" |
| LAUNCH_JSON_FILE = VSCODE_FOLDER_PATH / "launch.json" |
| |
| |
| def create_debug_configuration(component: str, port: int) -> dict: |
| """Create a debug configuration for a specific Airflow component.""" |
| return { |
| "name": f"Debug Airflow {COMPONENT_NAMES[component]}", |
| "type": "debugpy", |
| "request": "attach", |
| "justMyCode": False, |
| "connect": {"host": "localhost", "port": port}, |
| "pathMappings": [{"localRoot": "${workspaceFolder}", "remoteRoot": "/opt/airflow"}], |
| } |
| |
| |
| def create_launch_json_content() -> dict: |
| """Create the complete launch.json content with all debug configurations.""" |
| configurations = [] |
| |
| for component, port in DEBUG_PORTS.items(): |
| config = create_debug_configuration(component, port) |
| configurations.append(config) |
| |
| return {"version": "0.2.0", "configurations": configurations} |
| |
| |
| def setup_vscode(): |
| """Set up VSCode debug configurations for Airflow components.""" |
| print("[green]Creating[/] VSCode debug configurations for Airflow components...") |
| |
| # Create configurations for each component |
| for component, port in DEBUG_PORTS.items(): |
| print(f"[green]Adding[/] debug configuration: [blue]{COMPONENT_NAMES[component]}[/] (port {port})") |
| |
| # Create the launch.json content |
| launch_json_content = create_launch_json_content() |
| |
| # Ensure .vscode directory exists |
| VSCODE_FOLDER_PATH.mkdir(exist_ok=True) |
| |
| # Write the launch.json file |
| with open(LAUNCH_JSON_FILE, "w") as f: |
| json.dump(launch_json_content, f, indent=4) |
| |
| print(f"\n[green]Successfully created[/] {LAUNCH_JSON_FILE}") |
| |
| |
| def main(): |
| print("\n[yellow]VSCode Airflow Debug Configuration Setup[/]\n") |
| print("This script will create VSCode debug configurations for Airflow components:\n") |
| |
| for component, port in DEBUG_PORTS.items(): |
| print(f"* {COMPONENT_NAMES[component]}: port {port}") |
| |
| print(f"\nConfiguration will be written to: {LAUNCH_JSON_FILE}") |
| |
| if LAUNCH_JSON_FILE.exists(): |
| print(f"\n[yellow]Warning:[/] {LAUNCH_JSON_FILE} already exists!") |
| should_overwrite = Confirm.ask("Overwrite the existing file?") |
| if not should_overwrite: |
| print("[yellow]Skipped[/] - No changes made") |
| return |
| else: |
| should_continue = Confirm.ask("Create the debug configurations?") |
| if not should_continue: |
| print("[yellow]Skipped[/] - No changes made") |
| return |
| |
| setup_vscode() |
| |
| print("\n[green]Setup complete![/]") |
| print("\nFor more information, see: contributing-docs/20_debugging_airflow_components.rst") |
| |
| |
| if __name__ == "__main__": |
| main() |