### Install Dependencies with uv Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Use uv to synchronize development dependencies. Ensure graphviz is installed separately. ```shell uv sync --dev ``` -------------------------------- ### Install Ansible Playbook Grapher using uv Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Install the Ansible Playbook Grapher using the uv package manager. This is the recommended installation method. ```shell uv tool install ansible-playbook-grapher ``` -------------------------------- ### Install Ansible Playbook Grapher from GitHub using uv Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Install the latest unpublished version of Ansible Playbook Grapher directly from GitHub using uv. ```shell uv tool install "ansible-playbook-grapher @ git+https://github.com/haidaraM/ansible-playbook-grapher" ``` -------------------------------- ### Install Graphviz Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Install Graphviz, a dependency for the graphviz renderer, using your system's package manager. ```shell sudo apt-get install graphviz # or yum install or brew install ``` -------------------------------- ### Example Ansible Playbook: Simple Tasks Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt A basic Ansible playbook demonstrating tasks, vars, pre_tasks, and post_tasks. ```yaml # tests/fixtures/example.yml — simple tasks-only play - hosts: all vars: backport: "stretch-backports" packages: [git, tree, curl] pre_tasks: - name: Pre task 1 debug: msg="Pretask" tasks: - name: Add the backport apt_repository: repo: "deb http://ftp.debian.org/debian {{ backport }} main" state: present - name: Install packages apt: name: "{{ packages }}" state: present post_tasks: - name: Post task debug: msg="Post task 1" ``` -------------------------------- ### Install Ansible Playbook Grapher using pip Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Install the Ansible Playbook Grapher using pip. This is an alternative installation method. ```shell pip install ansible-playbook-grapher ``` -------------------------------- ### Print Version Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Displays the installed version of the ansible-playbook-grapher tool and the compatible ansible-core version. ```bash ansible-playbook-grapher --version # ansible-playbook-grapher 2.11.0-dev0 (with ansible 2.17.x) ``` -------------------------------- ### Install Ansible Playbook Grapher from GitHub using pip Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Install the latest unpublished version of Ansible Playbook Grapher directly from GitHub using pip. ```shell pip install "ansible-playbook-grapher @ git+https://github.com/haidaraM/ansible-playbook-grapher" ``` -------------------------------- ### Generate Graph for Example Playbook Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Basic usage to generate a graph for a given Ansible playbook file. ```shell ansible-playbook-grapher tests/fixtures/example.yml ``` -------------------------------- ### Install Ansible Galaxy Requirements Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Install Ansible Galaxy requirements for collections. Use --force if modifying collections. ```shell (cd tests/fixtures && ansible-galaxy install -r requirements.yml) ``` ```shell ansible-galaxy install -r requirements.yml --force ``` -------------------------------- ### Example Ansible Playbook: Roles and Tag Filtering Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt An Ansible playbook showcasing the use of roles with conditions and tags, along with task-level tag filtering. ```yaml # tests/fixtures/with_roles.yml — play using roles and tag filtering - hosts: all tags: [play1] roles: - role: fake_role when: ansible_distribution == "Debian" tags: [role_tag] - role: display_some_facts tasks: - name: Add backport {{ backport }} apt_repository: repo: "deb http://ftp.debian.org/debian {{ backport }} main" state: present ``` -------------------------------- ### Ansible Playbook with Nested Blocks and Roles Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt This playbook demonstrates nested blocks and the use of `include_role`. It includes tasks for installing Apache on CentOS and downloading a database dump. ```yaml - hosts: all pre_tasks: - name: Include role include_role: name: fake_role - name: Block in pre task block: - name: debug debug: msg: "pre task debug" tags: [pre_task_tag] tasks: - name: Install Apache when: ansible_facts['distribution'] == "CentOS" block: - name: Install some packages yum: name: "{{ item }}" with_items: [httpd, memcached] - block: - get_url: url: "{{ remote_database_dump }}" dest: "{{ local_database_dump }}" ``` -------------------------------- ### Python: PlaybookNode Class Usage Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt The `PlaybookNode` class represents the top-level playbook in the graph, containing `PlayNode` objects. It offers utilities for filtering and serialization. Examples include manual construction, removing empty plays, hiding plays without roles, calculating indices, and getting role usage. ```python from ansibleplaybookgrapher.graph_model import PlaybookNode, PlayNode, RoleNode # Typically obtained from PlaybookParser.parse() or Grapher.parse() # Manual construction example: pb_node = PlaybookNode(node_name="site.yml") play1 = PlayNode(node_name="Configure webservers", hosts=["web1", "web2"]) play2 = PlayNode(node_name="Configure databases", hosts=["db1"]) pb_node.add_node("plays", play1) pb_node.add_node("plays", play2) # Remove plays with no tasks (after tag filtering) pb_node.remove_empty_plays() # Hide plays that have no roles at the top level pb_node.hide_plays_without_roles() # Calculate sequential indices for all visible nodes pb_node.calculate_indices() # Get role usage across all plays roles_usage: dict = pb_node.roles_usage() for role, plays in roles_usage.items(): print(f"Role '{role.name}' used in plays: {[p.name for p in plays]}") # Serialize to dict (for JSON export) data = pb_node.to_dict() # data = { # "type": "PlaybookNode", # "id": "playbook_abc12345", # "name": "site.yml", # "when": "", # "index": 1, # "location": {"type": "file", "path": "/abs/path/site.yml", "line": 1, "column": 1}, # "plays": [...] # } ``` -------------------------------- ### Lint and Format Code with Ruff Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Run the lint and format command using make. ```shell make lint ``` -------------------------------- ### Use Custom Inventory Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a graph using a specified inventory file for variable interpolation and host-related data. ```bash ansible-playbook-grapher -i inventory/production site.yml ``` -------------------------------- ### Show Handlers Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a graph that includes handler tasks in addition to regular playbook tasks. ```bash ansible-playbook-grapher --show-handlers site.yml ``` -------------------------------- ### Run Tests and View Generated Files Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Execute all tests and automatically open generated graph files. Ensure TEST_VIEW_GENERATED_FILE is set. ```shell export TEST_VIEW_GENERATED_FILE=1 make test ``` -------------------------------- ### Generate Graph for Playbook with Blocks Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Visualize playbooks that utilize block structures. ```shell ansible-playbook-grapher tests/fixtures/with_block.yml ``` -------------------------------- ### JSON Output with Roles and Handlers Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a JSON representation of the playbook, including role tasks and handlers. ```bash ansible-playbook-grapher \ --renderer json \ --include-role-tasks \ --show-handlers \ site.yml ``` -------------------------------- ### Python: Using the Grapher Class Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt The `Grapher` class orchestrates the parsing of multiple playbooks. It delegates parsing to `PlaybookParser` and returns a list of `PlaybookNode` objects and a role-usage mapping. Use options like `tags`, `skip_tags`, `group_roles_by_name`, and `exclude_roles` for fine-grained control. ```python from ansibleplaybookgrapher.grapher import Grapher # Map of playbook argument strings to their resolved filesystem paths playbooks_mapping = { "site.yml": "/home/user/project/site.yml", "deploy.yml": "/home/user/project/deploy.yml", } grapher = Grapher(playbooks_mapping) playbook_nodes, roles_usage = grapher.parse( tags=["deploy"], # Only include tasks tagged 'deploy' skip_tags=["debug"], # Exclude tasks tagged 'debug' group_roles_by_name=True, # Merge roles with the same name into one node exclude_roles=["legacy_role", "deprecated_role"], ) for pb_node in playbook_nodes: print(f"Playbook: {pb_node.name}") for play in pb_node.plays: print(f" Play: {play.name} ({len(play.hosts)} hosts)") for task in play.get_all_tasks(): print(f" Task: {task.name}") # roles_usage maps each RoleNode to the set of PlayNodes that reference it for role, plays in roles_usage.items(): print(f"Role '{role.name}' used in: {[p.name for p in plays]}") ``` -------------------------------- ### Generate Graph Including Role Tasks Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Use the --include-role-tasks flag to visualize tasks within roles in the playbook graph. ```shell ansible-playbook-grapher --include-role-tasks tests/fixtures/with_roles.yml ``` -------------------------------- ### Basic SVG Output Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a basic SVG graph of the playbook structure. This is the default renderer. ```bash ansible-playbook-grapher site.yml ``` -------------------------------- ### Include Role Tasks and View Output Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates an SVG graph including tasks within roles and automatically opens the rendered graph in the default web browser. ```bash ansible-playbook-grapher --include-role-tasks --view site.yml ``` -------------------------------- ### Filter by Tags Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a graph, including only tasks tagged with 'deploy' and excluding tasks tagged with 'teardown'. ```bash ansible-playbook-grapher -t deploy --skip-tags teardown site.yml ``` -------------------------------- ### Open in VS Code Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Configures the rendered SVG to open files and folders in Visual Studio Code when nodes are double-clicked. ```bash ansible-playbook-grapher \ --open-protocol-handler vscode \ site.yml ``` -------------------------------- ### Python: Using the PlaybookParser Class Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt The `PlaybookParser` class parses a single Ansible playbook file into a `PlaybookNode` graph. It resolves imports, includes, roles, blocks, and handlers. Configure parsing with options like `playbook_path`, `tags`, `skip_tags`, `group_roles_by_name`, `playbook_name`, and `exclude_roles`. ```python from ansibleplaybookgrapher.parser import PlaybookParser parser = PlaybookParser( playbook_path="/home/user/project/site.yml", tags=["all"], skip_tags=[], group_roles_by_name=False, playbook_name="site.yml", # Display name (useful for collection playbooks) exclude_roles=["excluded_role"], ) playbook_node = parser.parse() print(f"Playbook: {playbook_node.name}") print(f"Number of plays: {len(playbook_node.plays)}") for play in playbook_node.plays: print(f"\nPlay '{play.name}':") print(f" Hosts: {play.hosts}") print(f" Pre-tasks: {len(play.pre_tasks)}") print(f" Roles: {len(play.roles)}") print(f" Tasks: {len(play.tasks)}") print(f" Post-tasks: {len(play.post_tasks)}") print(f" Handlers: {len(play.handlers)}") for role in play.roles: print(f" Role: {role.name} (include_role={role.include_role})") for task in role.tasks: print(f" Task: {task.name}, when={task.when}") ``` -------------------------------- ### Render Playbook to Mermaid Flowchart Syntax Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Utilize MermaidFlowChartRenderer to generate Mermaid syntax for embedding in Markdown. This renderer supports various Mermaid directives and layout orientations. The `view` parameter can open the diagram in a browser for live preview. ```python from ansibleplaybookgrapher.renderer.mermaid import MermaidFlowChartRenderer, DEFAULT_DIRECTIVE from ansibleplaybookgrapher.grapher import Grapher grapher = Grapher({"site.yml": "/project/site.yml"}) playbook_nodes, roles_usage = grapher.parse() for pb_node in playbook_nodes: pb_node.calculate_indices() renderer = MermaidFlowChartRenderer( playbook_nodes=playbook_nodes, roles_usage=roles_usage, ) mmd_path = renderer.render( open_protocol_handler="default", open_protocol_custom_formats=None, output_filename="/tmp/site_graph", title="Site Deployment", include_role_tasks=False, view=False, # If True, opens https://mermaid.live/ in browser show_handlers=False, directive=DEFAULT_DIRECTIVE, # '%%{ init: { "flowchart": { "curve": "bumpX" } } }%%' orientation="LR", # Left-to-right layout ) print(f"Mermaid file: {mmd_path}") # Mermaid file: /tmp/site_graph.mmd # Standalone: open any mermaid code in the browser MermaidFlowChartRenderer.view("flowchart LR\n A --> B") ``` -------------------------------- ### Utility Functions for ID Generation, Hashing, and Cleaning Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt These utility functions provide helpers for generating unique IDs, stable hash values, cleaning names for safe display, generating deterministic colors for plays, flattening 'when' conditions, and merging dictionaries. ```python from ansibleplaybookgrapher.utils import ( generate_id, hash_value, clean_name, get_play_colors, convert_when_to_str, merge_dicts, ) # Generate a short random ID with a prefix task_id = generate_id("task_") print(task_id) # e.g., "task_3f2a1b4c" play_id = generate_id("play_") print(play_id) # e.g., "play_a9c0d7e1" # Hash a string to 8-char hex (stable MD5 prefix) hashed = hash_value("my_role_name") print(hashed) # e.g., "1a2b3c4d" # Escape double quotes for Graphviz label safety safe = clean_name('Task with "quotes"') print(safe) # 'Task with "quotes"' # Generate a deterministic play color pair from the play ID main_color, font_color = get_play_colors("play_a9c0d7e1") print(main_color) # e.g., "#4a826b" print(font_color) # "#ffffff" # Flatten Ansible 'when' condition list to a display string when_str = convert_when_to_str(["ansible_os_family == 'Debian'", "pkg_install | bool"]) print(when_str) # "[when: ansible_os_family == 'Debian' and pkg_install | bool]" # Merge two role-usage dicts (union of play sets per role key) usage_a = {"role_x": {"play1", "play2"}} usage_b = {"role_x": {"play3"}, "role_y": {"play1"}} merged = merge_dicts(usage_a, usage_b) print(dict(merged)) # {"role_x": {"play1", "play2", "play3"}, "role_y": {"play1"}} ``` -------------------------------- ### Custom Output Filename Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Specifies a custom path and base filename for the output graph file. The appropriate extension is added automatically based on the renderer. ```bash ansible-playbook-grapher -o /tmp/output/my_graph site.yml ``` -------------------------------- ### Graph Multiple Playbooks Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a single combined graph from multiple playbook files specified as input. ```bash ansible-playbook-grapher site.yml deploy.yml rollback.yml -o combined ``` -------------------------------- ### Strip Path Prefix with Custom Protocol Handler Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Use the `--open-protocol-handler` and `--open-protocol-custom-formats` options to strip a path prefix, which is useful for containerized environments with path remapping. The custom format specifies how paths should be transformed. ```bash ansible-playbook-grapher \ --open-protocol-handler custom \ --open-protocol-custom-formats \ '{"file": "vscode://file/{path}:{line}:{column}", "folder": "{path}", "remove_from_path": "/workspace"}' \ site.yml ``` -------------------------------- ### Graph Playbook from Collection Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a graph for a playbook located within an Ansible collection, specified using its fully qualified collection name (FQCN). ```bash ansible-playbook-grapher my_namespace.my_collection.my_playbook ``` -------------------------------- ### Custom Open Protocol Handler Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Defines custom URL schemes for double-clicking nodes in the SVG, allowing integration with applications like VS Code for files and browsers for folders. ```bash ansible-playbook-grapher \ --open-protocol-handler custom \ --open-protocol-custom-formats \ '{"file": "vscode://file/{path}:{line}:{column}", "folder": "{path}"}' \ site.yml ``` -------------------------------- ### Generate Mermaid Flowchart for Multi-Play Playbook Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Generate a Mermaid flowchart for a playbook with multiple plays, including role tasks. ```shell ansible-playbook-grapher --include-role-tasks --renderer mermaid-flowchart tests/fixtures/multi-plays.yml ``` ```mermaid %%{ init: { "flowchart": { "curve": "bumpX" } } }%% flowchart LR %% Start of the playbook 'tests/fixtures/multi-plays.yml' playbook_a27d9bec("tests/fixtures/multi-plays.yml") %% Start of the play 'Play: all (0)' play_d6dd122d["Play: all (0)"] style play_d6dd122d stroke:#ba1a12,fill:#ba1a12,color:#ffffff playbook_a27d9bec --> |"1"| play_d6dd122d linkStyle 0 stroke:#ba1a12,color:#ba1a12 pre_task_676cdcb1["[pre_task] Pretask"] style pre_task_676cdcb1 stroke:#ba1a12,fill:#ffffff play_d6dd122d --> |"1"| pre_task_676cdcb1 linkStyle 1 stroke:#ba1a12,color:#ba1a12 pre_task_44476583["[pre_task] Pretask 2"] style pre_task_44476583 stroke:#ba1a12,fill:#ffffff play_d6dd122d --> |"2"| pre_task_44476583 linkStyle 2 stroke:#ba1a12,color:#ba1a12 %% Start of the role '[role] fake_role' play_d6dd122d --> |"3"| role_f0c07194 linkStyle 3 stroke:#ba1a12,color:#ba1a12 role_f0c07194(["[role] fake_role"]) style role_f0c07194 fill:#ba1a12,color:#ffffff,stroke:#ba1a12 task_90876ffc["[task] fake_role : Debug 1"] style task_90876ffc stroke:#ba1a12,fill:#ffffff role_f0c07194 --> |"1 [when: ansible_distribution == 'Debian']"| task_90876ffc linkStyle 4 stroke:#ba1a12,color:#ba1a12 task_bb701882["[task] fake_role : Debug 2"] style task_bb701882 stroke:#ba1a12,fill:#ffffff role_f0c07194 --> |"2 [when: ansible_distribution == 'Debian']"| task_bb701882 linkStyle 5 stroke:#ba1a12,color:#ba1a12 task_c00c5d61["[task] fake_role : Debug 3 with double quote "here" in the name"] style task_c00c5d61 stroke:#ba1a12,fill:#ffffff role_f0c07194 --> |"3 [when: ansible_distribution == 'Debian']"| task_c00c5d61 linkStyle 6 stroke:#ba1a12,color:#ba1a12 %% End of the role '[role] fake_role' %% Start of the role '[role] display_some_facts' play_d6dd122d --> |"4"| role_a168caef linkStyle 7 stroke:#ba1a12,color:#ba1a12 role_a168caef(["[role] display_some_facts"]) style role_a168caef fill:#ba1a12,color:#ffffff,stroke:#ba1a12 task_737e2be9["[task] display_some_facts : ansible_architecture"] style task_737e2be9 stroke:#ba1a12,fill:#ffffff role_a168caef --> |"1"| task_737e2be9 linkStyle 8 stroke:#ba1a12,color:#ba1a12 task_61bbb3fb["[task] display_some_facts : ansible_date_time"] style task_61bbb3fb stroke:#ba1a12,fill:#ffffff role_a168caef --> |"2"| task_61bbb3fb linkStyle 9 stroke:#ba1a12,color:#ba1a12 task_3b7308dc["[task] display_some_facts : Specific included task for Debian"] style task_3b7308dc stroke:#ba1a12,fill:#ffffff role_a168caef --> |"3"| task_3b7308dc linkStyle 10 stroke:#ba1a12,color:#ba1a12 %% End of the role '[role] display_some_facts' task_c8b76065["[task] Add backport {{backport}}"] style task_c8b76065 stroke:#ba1a12,fill:#ffffff play_d6dd122d --> |"5"| task_c8b76065 linkStyle 11 stroke:#ba1a12,color:#ba1a12 task_f7cebcbb["[task] Install packages"] style task_f7cebcbb stroke:#ba1a12,fill:#ffffff play_d6dd122d --> |"6"| task_f7cebcbb linkStyle 12 stroke:#ba1a12,color:#ba1a12 post_task_caafa665["[post_task] Posttask"] style post_task_caafa665 stroke:#ba1a12,fill:#ffffff play_d6dd122d --> |"7"| post_task_caafa665 linkStyle 13 stroke:#ba1a12,color:#ba1a12 post_task_b5ade468["[post_task] Posttask 2"] style post_task_b5ade468 stroke:#ba1a12,fill:#ffffff play_d6dd122d --> |"8"| post_task_b5ade468 linkStyle 14 stroke:#ba1a12,color:#ba1a12 %% End of the play 'Play: all (0)' %% Start of the play 'Play: database (0)' play_d780677e["Play: database (0)"] style play_d780677e stroke:#686864,fill:#686864,color:#ffffff playbook_a27d9bec --> |"2"| play_d780677e linkStyle 15 stroke:#686864,color:#686864 %% Start of the role '[role] fake_role' play_d780677e --> |"1"| role_1e6bf323 linkStyle 16 stroke:#686864,color:#686864 role_1e6bf323(["[role] fake_role"]) style role_1e6bf323 fill:#686864,color:#ffffff,stroke:#686864 task_3cb17d25["[task] fake_role : Debug 1"] style task_3cb17d25 stroke:#686864,fill:#ffffff role_1e6bf323 --> |"1 [when: ansible_distribution == 'Debian']"| task_3cb17d25 linkStyle 17 stroke:#686864,color:#686864 task_1f6232f4["[task] fake_role : Debug 2"] ``` -------------------------------- ### Group Roles by Name Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a graph where roles with identical names across different plays are consolidated into a single node. ```bash ansible-playbook-grapher --group-roles-by-name site.yml ``` -------------------------------- ### Mermaid Flowchart Output Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a Mermaid flowchart representation of the playbook, suitable for embedding in Markdown or GitHub. ```bash ansible-playbook-grapher --renderer mermaid-flowchart site.yml # Output: site.mmd ``` -------------------------------- ### JSON Output Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a JSON representation of the playbook's structure, providing machine-readable data. ```bash ansible-playbook-grapher --renderer json site.yml # Output: site.json ``` -------------------------------- ### Customize Mermaid Directive Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a Mermaid flowchart with custom initialization directives, allowing for theme and style adjustments. ```bash ansible-playbook-grapher \ --renderer mermaid-flowchart \ --renderer-mermaid-directive '%%{ init: { "theme": "dark", "flowchart": { "curve": "linear" } } }%%' \ site.yml ``` -------------------------------- ### Save Graphviz Dot Source Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates an SVG graph and saves the underlying Graphviz dot source file with a '.dot' extension alongside the SVG. ```bash ansible-playbook-grapher -s -o my_graph site.yml # Output: my_graph.svg, my_graph.dot ``` -------------------------------- ### Only Render Roles Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a graph that only displays role nodes, hiding individual task nodes within roles. ```bash ansible-playbook-grapher --only-roles site.yml ``` -------------------------------- ### TaskNode and HandlerNode Classes for Tasks and Handlers Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt TaskNode represents a single Ansible task, while HandlerNode extends it with 'listen' topics for handler notification resolution. Use these to define individual task and handler logic. ```python from ansibleplaybookgrapher.graph_model import TaskNode, HandlerNode, RoleNode # Regular task with conditional and notification task = TaskNode( node_name="Restart service", when="restart_needed | bool", notify=["reload nginx", "clear cache"], ) print(task.display_name()) # "[task] Restart service" print(task.notify) # ['reload nginx', 'clear cache'] print(task.has_loop()) # False (raw_object is None) # Handler responding to multiple notification names and listen topics handler = HandlerNode( node_name="reload nginx", listen=["reload web", "restart web server"], ) # Name matching (used internally by get_notified_handlers) print(handler.matches_name("reload nginx")) # True print(handler.matches_name("reload web")) # True (via listen) print(handler.matches_name("restart web server")) # True (via listen) print(handler.matches_name("unknown")) # False # Role-qualified handler name matching (e.g. "nginx : reload nginx") role = RoleNode(node_name="nginx") role.add_node("handlers", handler) print(handler.matches_name("nginx : reload nginx")) # True ``` -------------------------------- ### PlayNode Class Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Represents a single Ansible play, managing its composition types (pre_tasks, roles, tasks, post_tasks, handlers) and auto-generating colors for rendering. ```APIDOC ## PlayNode Class Represents a single Ansible play. Has five composition types: `pre_tasks`, `roles`, `tasks`, `post_tasks`, and `handlers`. Each play is automatically assigned a unique color for rendering. ```python from ansibleplaybookgrapher.graph_model import PlayNode, RoleNode, TaskNode, HandlerNode play = PlayNode( node_name="Deploy application", hosts=["app_servers"], ) # Colors are auto-generated from the play ID main_color, font_color = play.colors print(f"Play color: {main_color}, font: {font_color}") # e.g., '#3a7abf', '#ffffff' # Access composition sections print(play.pre_tasks) # list of TaskNode / BlockNode print(play.roles) # list of RoleNode (not include_role) print(play.tasks) # list of TaskNode / BlockNode / RoleNode (include_role) print(play.post_tasks) # list of TaskNode / BlockNode print(play.handlers) # list of HandlerNode # Check for handler notification task = TaskNode(node_name="Restart nginx", notify=["restart nginx"]) play.add_node("tasks", task) handler = HandlerNode(node_name="restart nginx", listen=["restart web"]) play.add_node("handlers", handler) # Resolve notified handlers (must call calculate_indices first) play.calculate_indices() notified, not_found = play.get_notified_handlers(["restart nginx"]) print(f"Notified: {[h.name for h in notified]}") # ['restart nginx'] print(f"Not found: {not_found}") # [] # Serialize (excludes handlers by default) data = play.to_dict() data_with_handlers = play.to_dict(include_handlers=True) ``` ``` -------------------------------- ### CLI: Vault and Extra Variables Options Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Manage vault-encrypted variables and pass extra variables using standard Ansible CLI options. Options include prompting for vault passwords, using password files, and specifying extra variables inline or from files. ```bash # Prompt for vault password ansible-playbook-grapher -J site.yml ``` ```bash # Use a vault password file ansible-playbook-grapher --vault-password-file ~/.vault_pass site.yml ``` ```bash # Pass extra variables (inline or file) ansible-playbook-grapher -e "env=production region=us-east-1" site.yml ``` ```bash ansible-playbook-grapher -e @vars/production.yml site.yml ``` ```bash # Use vault identity ansible-playbook-grapher --vault-id prod@~/.vault_pass site.yml ``` -------------------------------- ### Generate JSON graph from playbook Source: https://github.com/haidaram/ansible-playbook-grapher/blob/main/README.md Use this command to generate a JSON representation of your Ansible playbook, which can then be used for visualization. ```shell ansible-playbook-grapher --renderer json tests/fixtures/simple_playbook.yml ``` -------------------------------- ### Render Playbook to SVG with GraphvizRenderer Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Use GraphvizRenderer to convert playbook nodes into an SVG file. This renderer supports post-processing for embedded JavaScript, CSS, and interactive effects. It can also save a Graphviz DOT file. ```python from ansibleplaybookgrapher.renderer.graphviz import GraphvizRenderer from ansibleplaybookgrapher.grapher import Grapher grapher = Grapher({"site.yml": "/project/site.yml"}) playbook_nodes, roles_usage = grapher.parse() # Prepare and post-process each playbook node for pb_node in playbook_nodes: pb_node.remove_empty_plays() pb_node.calculate_indices() renderer = GraphvizRenderer( playbook_nodes=playbook_nodes, roles_usage=roles_usage, ) svg_path = renderer.render( open_protocol_handler="vscode", open_protocol_custom_formats=None, output_filename="/tmp/site_graph", title="My Site Playbook", include_role_tasks=True, view=False, show_handlers=True, save_dot_file=True, # Also write site_graph.dot collapsible_nodes=True, # Add +/- collapse buttons ) print(f"SVG written to: {svg_path}") # SVG written to: /tmp/site_graph.svg ``` -------------------------------- ### TaskNode and HandlerNode Classes Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt TaskNode represents a single Ansible task, while HandlerNode extends it to support `listen` topics and name-based matching for handler notifications. ```APIDOC ## TaskNode and HandlerNode classes `TaskNode` represents a single Ansible task. `HandlerNode` extends it with `listen` topics and name-based matching logic used for handler notification resolution. ```python from ansibleplaybookgrapher.graph_model import TaskNode, HandlerNode, RoleNode # Regular task with conditional and notification task = TaskNode( node_name="Restart service", when="restart_needed | bool", notify=["reload nginx", "clear cache"], ) print(task.display_name()) # "[task] Restart service" print(task.notify) # ['reload nginx', 'clear cache'] print(task.has_loop()) # False (raw_object is None) # Handler responding to multiple notification names and listen topics handler = HandlerNode( node_name="reload nginx", listen=["reload web", "restart web server"], ) # Name matching (used internally by get_notified_handlers) print(handler.matches_name("reload nginx")) # True print(handler.matches_name("reload web")) # True (via listen) print(handler.matches_name("restart web server")) # True (via listen) print(handler.matches_name("unknown")) # False # Role-qualified handler name matching (e.g. "nginx : reload nginx") role = RoleNode(node_name="nginx") role.add_node("handlers", handler) print(handler.matches_name("nginx : reload nginx")) # True ``` ``` -------------------------------- ### RoleNode Class Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Represents an Ansible role, supporting both static `roles:` references and dynamic `include_role` tasks. Roles used in multiple plays are rendered in black. ```APIDOC ## RoleNode Class Represents an Ansible role in the graph. Supports both static `roles:` references and dynamic `include_role` tasks. Roles used in multiple plays are rendered in black to indicate shared usage. ```python from ansibleplaybookgrapher.graph_model import RoleNode, TaskNode # Static role (from 'roles:' section) static_role = RoleNode( node_name="nginx", include_role=False, # static import ) # Dynamic include_role task dynamic_role = RoleNode( node_name="nginx", include_role=True, # dynamic include ) # Add tasks to the role task = TaskNode(node_name="Install nginx package") static_role.add_node("tasks", task) # Check if role has a loop (only possible for include_role) print(dynamic_role.has_loop()) # False unless raw_object has .loop # Check emptiness print(static_role.is_empty()) # False (has one task) # Serialize with tasks and handlers data = static_role.to_dict( include_role_tasks=True, include_handlers=True, ) # data["tasks"] will contain the serialized task list # data["include_role"] = False ``` ``` -------------------------------- ### Render Playbook to Structured JSON Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt The JSONRenderer converts playbook graphs into a detailed JSON format. This schema includes node hierarchy, locations, colors, and role/task relationships, useful for programmatic analysis or custom visualizations. ```python from ansibleplaybookgrapher.renderer.json import JSONRenderer from ansibleplaybookgrapher.grapher import Grapher grapher = Grapher({"site.yml": "/project/site.yml"}) playbook_nodes, roles_usage = grapher.parse() for pb_node in playbook_nodes: pb_node.calculate_indices() renderer = JSONRenderer( playbook_nodes=playbook_nodes, roles_usage=roles_usage, ) json_path = renderer.render( open_protocol_handler="default", open_protocol_custom_formats=None, output_filename="/tmp/site_graph", title="Site Playbook", include_role_tasks=True, view=False, show_handlers=True, ) print(f"JSON written to: {json_path}") # JSON written to: /tmp/site_graph.json # Expected JSON structure: # { # "version": 1, # "title": "Site Playbook", # "playbooks": [ # { # "type": "PlaybookNode", # "id": "playbook_a1b2c3d4", # "name": "site.yml", # "location": {"type": "file", "path": "/project/site.yml", "line": 1, "column": 1}, # "plays": [ # { # "type": "PlayNode", # "id": "play_e5f6g7h8", # "name": "Deploy", # "hosts": ["web"], # "colors": {"main": "#4a826b", "font": "#ffffff"}, # "pre_tasks": [], # "roles": [...], # "tasks": [...], # "post_tasks": [], # "handlers": [...] # } # ] # } # ] # } ``` -------------------------------- ### BlockNode Class Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Represents an Ansible `block:` grouping, rendered as a Graphviz cluster. The `when` condition is inherited by all tasks within the block. ```APIDOC ## BlockNode Class Represents an Ansible `block:` grouping. Rendered as a Graphviz cluster (subgraph) instead of a regular node. The `when` condition is inherited by all tasks inside the block (matching Ansible's own behavior). ```python from ansibleplaybookgrapher.graph_model import BlockNode, TaskNode, PlayNode play = PlayNode(node_name="Setup servers", hosts=["all"]) block = BlockNode( node_name="Install packages", when="ansible_os_family == 'Debian'", ) task1 = TaskNode(node_name="apt-get update") task2 = TaskNode(node_name="apt-get install nginx") # BlockNode routes all additions to "tasks" regardless of composition name block.add_node("tasks", task1) block.add_node("tasks", task2) play.add_node("tasks", block) play.calculate_indices() # Get display name print(block.display_name()) # "[block] Install packages" # Traversal print(block.tasks) # [task1, task2] print(block.is_empty()) # False ``` ``` -------------------------------- ### Exclude Roles by Name Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a graph, excluding specified roles by their names. ```bash ansible-playbook-grapher --exclude-roles "base_role,legacy_role" site.yml ``` -------------------------------- ### Post-process SVG with GraphvizPostProcessor Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Enhance raw SVG files generated by Graphviz using GraphvizPostProcessor. This class embeds necessary JavaScript, CSS, and applies interactive effects like hover and collapsible nodes. It can overwrite the original file or write to a new path. ```python from ansibleplaybookgrapher.renderer.graphviz.postprocessor import GraphvizPostProcessor # Typically called automatically by GraphvizRenderer; shown here for custom use processor = GraphvizPostProcessor(svg_path="/tmp/site_graph.svg") # Inject JS, CSS, hover effects, and link metadata for all playbook nodes processor.post_process( playbook_nodes=playbook_nodes, collapsible_nodes=True, # Add +/- buttons on play/role/block nodes ) # Write back to the same file (or a new path) processor.write() # overwrite original processor.write("/tmp/site_graph_enhanced.svg") # write to new file ``` -------------------------------- ### NodeLocation Dataclass for File and Folder Tracking Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Use NodeLocation to track filesystem paths for tasks, plays, and playbooks. It supports 'file' and 'folder' types. An invalid type will raise a ValueError. ```python from ansibleplaybookgrapher.graph_model import NodeLocation # File location (tasks, plays, playbooks) file_loc = NodeLocation( type="file", path="/project/roles/nginx/tasks/main.yml", line=12, column=5, ) # Folder location (static roles) folder_loc = NodeLocation( type="folder", path="/project/roles/nginx", ) print(file_loc.type) # "file" print(folder_loc.type) # "folder" # Invalid type raises ValueError try: bad_loc = NodeLocation(type="symlink") except ValueError as e: print(e) # Type 'symlink' not supported. Valid values: file, folder. ``` -------------------------------- ### Exclude Roles from File Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a graph, excluding roles listed in a specified text file, with one role name per line. ```bash ansible-playbook-grapher --exclude-roles ./excluded_roles.txt site.yml ``` -------------------------------- ### Collapsible Nodes Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates an SVG graph with interactive buttons on play, role, and block nodes, allowing them to be collapsed or expanded. ```bash ansible-playbook-grapher --collapsible-nodes site.yml ``` -------------------------------- ### Change Mermaid Orientation Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a Mermaid flowchart with a specified orientation (e.g., TD for top-down, LR for left-to-right). ```bash ansible-playbook-grapher \ --renderer mermaid-flowchart \ --renderer-mermaid-orientation TD \ site.yml ``` -------------------------------- ### RoleNode Class for Representing Ansible Roles Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Use RoleNode to represent an Ansible role, supporting both static 'roles:' references and dynamic 'include_role' tasks. Roles used in multiple plays are rendered in black. ```python from ansibleplaybookgrapher.graph_model import RoleNode, TaskNode # Static role (from 'roles:' section) static_role = RoleNode( node_name="nginx", include_role=False, # static import ) # Dynamic include_role task dynamic_role = RoleNode( node_name="nginx", include_role=True, # dynamic include ) # Add tasks to the role task = TaskNode(node_name="Install nginx package") static_role.add_node("tasks", task) # Check if role has a loop (only possible for include_role) print(dynamic_role.has_loop()) # False unless raw_object has .loop # Check emptiness print(static_role.is_empty()) # False (has one task) # Serialize with tasks and handlers data = static_role.to_dict( include_role_tasks=True, include_handlers=True, ) # data["tasks"] will contain the serialized task list # data["include_role"] = False ``` -------------------------------- ### Hide Empty Plays Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Generates a graph, omitting plays that contain no tasks after tag filtering has been applied. ```bash ansible-playbook-grapher --hide-empty-plays site.yml ``` -------------------------------- ### PlayNode Class for Representing Ansible Plays Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Use PlayNode to represent a single Ansible play. It manages composition types like pre_tasks, roles, tasks, post_tasks, and handlers, and automatically assigns unique colors for rendering. ```python from ansibleplaybookgrapher.graph_model import PlayNode, RoleNode, TaskNode, HandlerNode play = PlayNode( node_name="Deploy application", hosts=["app_servers"], ) # Colors are auto-generated from the play ID main_color, font_color = play.colors print(f"Play color: {main_color}, font: {font_color}") # e.g., '#3a7abf', '#ffffff' # Access composition sections print(play.pre_tasks) # list of TaskNode / BlockNode print(play.roles) # list of RoleNode (not include_role) print(play.tasks) # list of TaskNode / BlockNode / RoleNode (include_role) print(play.post_tasks) # list of TaskNode / BlockNode print(play.handlers) # list of HandlerNode # Check for handler notification task = TaskNode(node_name="Restart nginx", notify=["restart nginx"]) play.add_node("tasks", task) handler = HandlerNode(node_name="restart nginx", listen=["restart web"]) play.add_node("handlers", handler) # Resolve notified handlers (must call calculate_indices first) play.calculate_indices() notified, not_found = play.get_notified_handlers(["restart nginx"]) print(f"Notified: {[h.name for h in notified]}") # ['restart nginx'] print(f"Not found: {not_found}") # [] # Serialize (excludes handlers by default) data = play.to_dict() data_with_handlers = play.to_dict(include_handlers=True) ``` -------------------------------- ### BlockNode Class for Ansible Block Groupings Source: https://context7.com/haidaram/ansible-playbook-grapher/llms.txt Use BlockNode to represent an Ansible 'block:' grouping, rendered as a Graphviz cluster. The 'when' condition is inherited by all tasks within the block. ```python from ansibleplaybookgrapher.graph_model import BlockNode, TaskNode, PlayNode play = PlayNode(node_name="Setup servers", hosts=["all"]) block = BlockNode( node_name="Install packages", when="ansible_os_family == 'Debian'", ) task1 = TaskNode(node_name="apt-get update") task2 = TaskNode(node_name="apt-get install nginx") # BlockNode routes all additions to "tasks" regardless of composition name block.add_node("tasks", task1) block.add_node("tasks", task2) play.add_node("tasks", block) play.calculate_indices() # Get display name print(block.display_name()) # "[block] Install packages" # Traversal print(block.tasks) # [task1, task2] print(block.is_empty()) # False ```