Giter VIP home page Giter VIP logo

ansible-playbook-grapher's Introduction

Ansible Playbook Grapher

Testing PyPI version Coverage Status

ansible-playbook-grapher is a command line tool to create a graph representing your Ansible playbook plays, tasks and roles. The aim of this project is to have an overview of your playbook.

Inspired by Ansible Inventory Grapher.

Features

The following features are available when opening the SVGs in a browser (recommended) or a viewer that supports JavaScript:

  • Highlighting of all the related nodes of a given node when clicking or hovering. Example: Click on a role to select all its tasks when --include-role-tasks is set.
  • A double click on a node opens the corresponding file or folder depending whether if it's a playbook, a play, a task or a role. By default, the browser will open folders and download files since it may not be able to render the YAML file.
    Optionally, you can set the open protocol to use VSCode with --open-protocol-handler vscode: it will open the folders when double-clicking on roles (not include_role) and the files for the others nodes. The cursor will be at the task exact position in the file.
    Lastly, you can provide your own protocol formats with --open-protocol-handler custom --open-protocol-custom-formats '{}'. See the help and an example.
  • Filer tasks based on tags
  • Export the dot file used to generate the graph with Graphviz.

Prerequisites

  • Python 3.10 at least. Might work with some previous versions but the code is NOT tested against them. See support matrix.
  • A virtual environment from which to run the grapher. This is highly recommended because the grapher depends on some versions of ansible-core which are not necessarily installed in your environment and may cause issues if you use some older versions of Ansible ( since ansible package has been split).
  • Graphviz: The tool used to generate the graph in SVG.
    sudo apt-get install graphviz # or yum install or brew install

I try to respect Red Hat Ansible Engine Life Cycle for the supported Ansible version.

Installation

pip install ansible-playbook-grapher

You can also install the unpublished version from GitHub direction. Examples:

# Install the version from the main branch
pip install "ansible-playbook-grapher @ git+https://github.com/haidaraM/ansible-playbook-grapher"

# Install the version from a specific branch
pip install "ansible-playbook-grapher @ git+https://github.com/haidaraM/ansible-playbook-grapher@specific-branch"

Renderers

At the time of writing, two renderers are supported:

  1. graphviz (default): Generate the graph in SVG. It has more features and is more tested: open protocol, highlight linked nodes...
  2. mermaid-flowchart: Generate the graph in Mermaid format. You can directly embed the graph in your markdown and GitHub ( and other integrations) will render it. Early support.

If you are interested to support more renderers, feel free to create an issue or raise a PR based on the existing renderers.

Usage

ansible-playbook-grapher tests/fixtures/example.yml

Example

ansible-playbook-grapher --include-role-tasks  tests/fixtures/with_roles.yml

Example

ansible-playbook-grapher tests/fixtures/with_block.yml

Example

ansible-playbook-grapher --include-role-tasks --renderer mermaid-flowchart tests/fixtures/multi-plays.yml
---
title: Ansible Playbook Grapher
---
%%{ init: { "flowchart": { "curve": "bumpX" } } }%%
flowchart LR
	%% Start of the playbook 'tests/fixtures/multi-plays.yml'
	playbook_34b89e53("tests/fixtures/multi-plays.yml")
		%% Start of the play 'Play: all (0)'
		play_8c4134b8["Play: all (0)"]
		style play_8c4134b8 fill:#656f5d,color:#ffffff
		playbook_34b89e53 --> |"1"| play_8c4134b8
		linkStyle 0 stroke:#656f5d,color:#656f5d
			pre_task_dd2c1b7d["[pre_task]  Pretask"]
			style pre_task_dd2c1b7d stroke:#656f5d,fill:#ffffff
			play_8c4134b8 --> |"1"| pre_task_dd2c1b7d
			linkStyle 1 stroke:#656f5d,color:#656f5d
			pre_task_bc33639f["[pre_task]  Pretask 2"]
			style pre_task_bc33639f stroke:#656f5d,fill:#ffffff
			play_8c4134b8 --> |"2"| pre_task_bc33639f
			linkStyle 2 stroke:#656f5d,color:#656f5d
			%% Start of the role 'fake_role'
			play_8c4134b8 --> |"3"| role_f4e6fb4d
			linkStyle 3 stroke:#656f5d,color:#656f5d
			role_f4e6fb4d("[role] fake_role")
			style role_f4e6fb4d fill:#656f5d,color:#ffffff,stroke:#656f5d
				task_94f7fc58[" fake_role : Debug 1"]
				style task_94f7fc58 stroke:#656f5d,fill:#ffffff
				role_f4e6fb4d --> |"1 [when: ansible_distribution == 'Debian']"| task_94f7fc58
				linkStyle 4 stroke:#656f5d,color:#656f5d
				task_bd56c6b5[" fake_role : Debug 2"]
				style task_bd56c6b5 stroke:#656f5d,fill:#ffffff
				role_f4e6fb4d --> |"2 [when: ansible_distribution == 'Debian']"| task_bd56c6b5
				linkStyle 5 stroke:#656f5d,color:#656f5d
				task_4f51a1cc[" fake_role : Debug 3 with double quote "here" in the name"]
				style task_4f51a1cc stroke:#656f5d,fill:#ffffff
				role_f4e6fb4d --> |"3 [when: ansible_distribution == 'Debian']"| task_4f51a1cc
				linkStyle 6 stroke:#656f5d,color:#656f5d
			%% End of the role 'fake_role'
			%% Start of the role 'display_some_facts'
			play_8c4134b8 --> |"4"| role_497b8470
			linkStyle 7 stroke:#656f5d,color:#656f5d
			role_497b8470("[role] display_some_facts")
			style role_497b8470 fill:#656f5d,color:#ffffff,stroke:#656f5d
				task_984b3c44[" display_some_facts : ansible_architecture"]
				style task_984b3c44 stroke:#656f5d,fill:#ffffff
				role_497b8470 --> |"1"| task_984b3c44
				linkStyle 8 stroke:#656f5d,color:#656f5d
				task_3cb4a46c[" display_some_facts : ansible_date_time"]
				style task_3cb4a46c stroke:#656f5d,fill:#ffffff
				role_497b8470 --> |"2"| task_3cb4a46c
				linkStyle 9 stroke:#656f5d,color:#656f5d
				task_715c2049[" display_some_facts : Specific included task for Debian"]
				style task_715c2049 stroke:#656f5d,fill:#ffffff
				role_497b8470 --> |"3"| task_715c2049
				linkStyle 10 stroke:#656f5d,color:#656f5d
			%% End of the role 'display_some_facts'
			task_d8b579ea["[task]  Add backport {{backport}}"]
			style task_d8b579ea stroke:#656f5d,fill:#ffffff
			play_8c4134b8 --> |"5"| task_d8b579ea
			linkStyle 11 stroke:#656f5d,color:#656f5d
			task_99117197["[task]  Install packages"]
			style task_99117197 stroke:#656f5d,fill:#ffffff
			play_8c4134b8 --> |"6"| task_99117197
			linkStyle 12 stroke:#656f5d,color:#656f5d
			post_task_f789bda0["[post_task]  Posttask"]
			style post_task_f789bda0 stroke:#656f5d,fill:#ffffff
			play_8c4134b8 --> |"7"| post_task_f789bda0
			linkStyle 13 stroke:#656f5d,color:#656f5d
			post_task_08755b4b["[post_task]  Posttask 2"]
			style post_task_08755b4b stroke:#656f5d,fill:#ffffff
			play_8c4134b8 --> |"8"| post_task_08755b4b
			linkStyle 14 stroke:#656f5d,color:#656f5d
		%% End of the play 'Play: all (0)'
		%% Start of the play 'Play: database (0)'
		play_40fea3c6["Play: database (0)"]
		style play_40fea3c6 fill:#2370a9,color:#ffffff
		playbook_34b89e53 --> |"2"| play_40fea3c6
		linkStyle 15 stroke:#2370a9,color:#2370a9
			%% Start of the role 'fake_role'
			play_40fea3c6 --> |"1"| role_38fdd7bb
			linkStyle 16 stroke:#2370a9,color:#2370a9
			role_38fdd7bb("[role] fake_role")
			style role_38fdd7bb fill:#2370a9,color:#ffffff,stroke:#2370a9
				task_54a811a1[" fake_role : Debug 1"]
				style task_54a811a1 stroke:#2370a9,fill:#ffffff
				role_38fdd7bb --> |"1 [when: ansible_distribution == 'Debian']"| task_54a811a1
				linkStyle 17 stroke:#2370a9,color:#2370a9
				task_0400749b[" fake_role : Debug 2"]
				style task_0400749b stroke:#2370a9,fill:#ffffff
				role_38fdd7bb --> |"2 [when: ansible_distribution == 'Debian']"| task_0400749b
				linkStyle 18 stroke:#2370a9,color:#2370a9
				task_e453cadd[" fake_role : Debug 3 with double quote "here" in the name"]
				style task_e453cadd stroke:#2370a9,fill:#ffffff
				role_38fdd7bb --> |"3 [when: ansible_distribution == 'Debian']"| task_e453cadd
				linkStyle 19 stroke:#2370a9,color:#2370a9
			%% End of the role 'fake_role'
			%% Start of the role 'display_some_facts'
			play_40fea3c6 --> |"2"| role_b05b7094
			linkStyle 20 stroke:#2370a9,color:#2370a9
			role_b05b7094("[role] display_some_facts")
			style role_b05b7094 fill:#2370a9,color:#ffffff,stroke:#2370a9
				task_153db06e[" display_some_facts : ansible_architecture"]
				style task_153db06e stroke:#2370a9,fill:#ffffff
				role_b05b7094 --> |"1"| task_153db06e
				linkStyle 21 stroke:#2370a9,color:#2370a9
				task_13df99ce[" display_some_facts : ansible_date_time"]
				style task_13df99ce stroke:#2370a9,fill:#ffffff
				role_b05b7094 --> |"2"| task_13df99ce
				linkStyle 22 stroke:#2370a9,color:#2370a9
				task_369b5720[" display_some_facts : Specific included task for Debian"]
				style task_369b5720 stroke:#2370a9,fill:#ffffff
				role_b05b7094 --> |"3"| task_369b5720
				linkStyle 23 stroke:#2370a9,color:#2370a9
			%% End of the role 'display_some_facts'
		%% End of the play 'Play: database (0)'
		%% Start of the play 'Play: webserver (0)'
		play_a68ff4e7["Play: webserver (0)"]
		style play_a68ff4e7 fill:#a905c7,color:#ffffff
		playbook_34b89e53 --> |"3"| play_a68ff4e7
		linkStyle 24 stroke:#a905c7,color:#a905c7
			%% Start of the role 'nested_include_role'
			play_a68ff4e7 --> |"1"| role_8bcf64e2
			linkStyle 25 stroke:#a905c7,color:#a905c7
			role_8bcf64e2("[role] nested_include_role")
			style role_8bcf64e2 fill:#a905c7,color:#ffffff,stroke:#a905c7
				task_bd87cdf3[" nested_include_role : Ensure postgresql is at the latest version"]
				style task_bd87cdf3 stroke:#a905c7,fill:#ffffff
				role_8bcf64e2 --> |"1"| task_bd87cdf3
				linkStyle 26 stroke:#a905c7,color:#a905c7
				task_d7674c4b[" nested_include_role : Ensure that postgresql is started"]
				style task_d7674c4b stroke:#a905c7,fill:#ffffff
				role_8bcf64e2 --> |"2"| task_d7674c4b
				linkStyle 27 stroke:#a905c7,color:#a905c7
				%% Start of the role 'display_some_facts'
				role_8bcf64e2 --> |"3 [when: x is not defined]"| role_806214e1
				linkStyle 28 stroke:#a905c7,color:#a905c7
				role_806214e1("[role] display_some_facts")
				style role_806214e1 fill:#a905c7,color:#ffffff,stroke:#a905c7
					task_b1fb63fd[" display_some_facts : ansible_architecture"]
					style task_b1fb63fd stroke:#a905c7,fill:#ffffff
					role_806214e1 --> |"1"| task_b1fb63fd
					linkStyle 29 stroke:#a905c7,color:#a905c7
					task_4a1319fd[" display_some_facts : ansible_date_time"]
					style task_4a1319fd stroke:#a905c7,fill:#ffffff
					role_806214e1 --> |"2"| task_4a1319fd
					linkStyle 30 stroke:#a905c7,color:#a905c7
					task_175005a1[" display_some_facts : Specific included task for Debian"]
					style task_175005a1 stroke:#a905c7,fill:#ffffff
					role_806214e1 --> |"3"| task_175005a1
					linkStyle 31 stroke:#a905c7,color:#a905c7
				%% End of the role 'display_some_facts'
				%% Start of the role 'fake_role'
				role_8bcf64e2 --> |"4"| role_557d6933
				linkStyle 32 stroke:#a905c7,color:#a905c7
				role_557d6933("[role] fake_role")
				style role_557d6933 fill:#a905c7,color:#ffffff,stroke:#a905c7
					task_1fa41f3c[" fake_role : Debug 1"]
					style task_1fa41f3c stroke:#a905c7,fill:#ffffff
					role_557d6933 --> |"1"| task_1fa41f3c
					linkStyle 33 stroke:#a905c7,color:#a905c7
					task_2841d72b[" fake_role : Debug 2"]
					style task_2841d72b stroke:#a905c7,fill:#ffffff
					role_557d6933 --> |"2"| task_2841d72b
					linkStyle 34 stroke:#a905c7,color:#a905c7
					task_e5fef12a[" fake_role : Debug 3 with double quote "here" in the name"]
					style task_e5fef12a stroke:#a905c7,fill:#ffffff
					role_557d6933 --> |"3"| task_e5fef12a
					linkStyle 35 stroke:#a905c7,color:#a905c7
				%% End of the role 'fake_role'
			%% End of the role 'nested_include_role'
			%% Start of the role 'display_some_facts'
			play_a68ff4e7 --> |"2"| role_2720d5bc
			linkStyle 36 stroke:#a905c7,color:#a905c7
			role_2720d5bc("[role] display_some_facts")
			style role_2720d5bc fill:#a905c7,color:#ffffff,stroke:#a905c7
				task_4d8d8def[" display_some_facts : ansible_architecture"]
				style task_4d8d8def stroke:#a905c7,fill:#ffffff
				role_2720d5bc --> |"1"| task_4d8d8def
				linkStyle 37 stroke:#a905c7,color:#a905c7
				task_58aea4f6[" display_some_facts : ansible_date_time"]
				style task_58aea4f6 stroke:#a905c7,fill:#ffffff
				role_2720d5bc --> |"2"| task_58aea4f6
				linkStyle 38 stroke:#a905c7,color:#a905c7
				task_800f91e9[" display_some_facts : Specific included task for Debian"]
				style task_800f91e9 stroke:#a905c7,fill:#ffffff
				role_2720d5bc --> |"3"| task_800f91e9
				linkStyle 39 stroke:#a905c7,color:#a905c7
			%% End of the role 'display_some_facts'
		%% End of the play 'Play: webserver (0)'
	%% End of the playbook 'tests/fixtures/multi-plays.yml'

Note on block: Since blocks are logical group of tasks, the conditional when is not displayed on the edges pointing to them but on the tasks inside the block. This mimics Ansible behavior regarding the blocks.

CLI options

The available options:

usage: ansible-playbook-grapher [-h] [-v] [-i INVENTORY]
                                [--include-role-tasks] [-s] [--view]
                                [-o OUTPUT_FILENAME]
                                [--open-protocol-handler {default,vscode,custom}]
                                [--open-protocol-custom-formats OPEN_PROTOCOL_CUSTOM_FORMATS]
                                [--group-roles-by-name]
                                [--renderer {graphviz,mermaid-flowchart}]
                                [--renderer-mermaid-directive RENDERER_MERMAID_DIRECTIVE]
                                [--renderer-mermaid-orientation {TD,RL,BT,RL,LR}]
                                [--version] [-t TAGS] [--skip-tags SKIP_TAGS]
                                [--vault-id VAULT_IDS]
                                [--ask-vault-password | --vault-password-file VAULT_PASSWORD_FILES]
                                [-e EXTRA_VARS]
                                playbooks [playbooks ...]

Make graphs from your Ansible Playbooks.

positional arguments:
  playbooks             Playbook(s) to graph

options:
  --ask-vault-password, --ask-vault-pass
                        ask for vault password
  --group-roles-by-name
                        When rendering the graph, only a single role will be
                        display for all roles having the same names. Default:
                        False
  --include-role-tasks  Include the tasks of the role in the graph.
  --open-protocol-custom-formats OPEN_PROTOCOL_CUSTOM_FORMATS
                        The custom formats to use as URLs for the nodes in the
                        graph. Required if --open-protocol-handler is set to
                        custom. You should provide a JSON formatted string
                        like: {"file": "", "folder": ""}. Example: If you want
                        to open folders (roles) inside the browser and files
                        (tasks) in vscode, set it to: '{"file":
                        "vscode://file/{path}:{line}:{column}", "folder":
                        "{path}"}'. path: the absolute path to the file
                        containing the the plays/tasks/roles. line/column: the
                        position of the plays/tasks/roles in the file. You can
                        optionally add the attribute "remove_from_path" to
                        remove some parts of the path if you want relative
                        paths.
  --open-protocol-handler {default,vscode,custom}
                        The protocol to use to open the nodes when double-
                        clicking on them in your SVG viewer. Your SVG viewer
                        must support double-click and Javascript. The
                        supported values are 'default', 'vscode' and 'custom'.
                        For 'default', the URL will be the path to the file or
                        folders. When using a browser, it will open or
                        download them. For 'vscode', the folders and files
                        will be open with VSCode. For 'custom', you need to
                        set a custom format with --open-protocol-custom-
                        formats.
  --renderer {graphviz,mermaid-flowchart}
                        The renderer to use to generate the graph. Default:
                        graphviz
  --renderer-mermaid-directive RENDERER_MERMAID_DIRECTIVE
                        The directive for the mermaid renderer. Can be used to
                        customize the output: fonts, theme, curve etc. More
                        info at https://mermaid.js.org/config/directives.html.
                        Default: '%%{ init: { "flowchart": { "curve": "bumpX" } } }%%'
  --renderer-mermaid-orientation {TD,RL,BT,RL,LR}
                        The orientation of the flow chart. Default: 'LR'
  --skip-tags SKIP_TAGS
                        only run plays and tasks whose tags do not match these
                        values
  --vault-id VAULT_IDS  the vault identity to use
  --vault-password-file VAULT_PASSWORD_FILES, --vault-pass-file VAULT_PASSWORD_FILES
                        vault password file
  --version             show program's version number and exit
  --view                Automatically open the resulting SVG file with your
                        system’s default viewer application for the file type
  -e EXTRA_VARS, --extra-vars EXTRA_VARS
                        set additional variables as key=value or YAML/JSON, if
                        filename prepend with @
  -h, --help            show this help message and exit
  -i INVENTORY, --inventory INVENTORY
                        specify inventory host path or comma separated host
                        list.
  -o OUTPUT_FILENAME, --output-file-name OUTPUT_FILENAME
                        Output filename without the '.svg' extension. Default:
                        <playbook>.svg
  -s, --save-dot-file   Save the graphviz dot file used to generate the graph.
  -t TAGS, --tags TAGS  only run plays and tasks tagged with these values
  -v, --verbose         Causes Ansible to print more debug messages. Adding
                        multiple -v will increase the verbosity, the builtin
                        plugins currently evaluate up to -vvvvvv. A reasonable
                        level to start is -vvv, connection debugging might
                        require -vvvv.

Configuration: ansible.cfg

The content of ansible.cfg is loaded automatically when running the grapher according to Ansible's behavior. The corresponding environment variables are also loaded.

The values in the config file (and their corresponding environment variables) may affect the behavior of the grapher. For example TAGS_RUN and TAGS_SKIP or vault configuration.

More information here.

Limitations

  • Since Ansible Playbook Grapher is a static analyzer that parses your playbook, it's limited to what can be determined statically: no task is run against your inventory. The parser tries to interpolate the variables, but some of them are only available when running your playbook ( ansible_os_family, ansible_system, etc.). The tasks inside any import_* or include_* with some variables in their arguments may not appear in the graph.
  • The rendered SVG graph may sometime display tasks in a wrong order. I cannot control this behavior of Graphviz yet. Always check the edge label to know the tasks order.
  • The label of the edges may overlap with each other. They are positioned so that they are as close as possible to the target nodes. If the same role is used in multiple plays or playbooks, the labels can overlap.

Contribution

Contributions are welcome. Feel free to contribute by creating an issue or submitting a PR 😃

Dev environment

To setup a new development environment :

  • Install graphviz (see above)
  • (cd tests && pip install -r requirements_tests.txt)

Run the tests and open the generated files in your system’s default viewer application:

export TEST_VIEW_GENERATED_FILE=1
make test # run all tests

The graphs are generated in the folder tests/generated-svgs. They are also generated as artefacts in Github Actions. Feel free to look at them when submitting PRs.

Lint and format

The project uses black to format the code. Run black . to format.

License

GNU General Public License v3.0 or later (Same as Ansible)

See LICENSE for the full text

ansible-playbook-grapher's People

Contributors

adamchainz avatar dependabot-preview[bot] avatar dependabot[bot] avatar haidaram avatar jheidbrink avatar nvtkaszpir avatar petermosmans avatar ros0x5ft avatar sonulohani avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ansible-playbook-grapher's Issues

Does the tool have run playbooks first?

Hi,

I was testing the ansible-playbook-grapher on an ansible playbooks. From my understanding, the tool is meant to simply graph a playbook and provide you with a graphical overview. However, when attempting to do so, it appeared that the tool attempts to run the playbook first. Is that correct or have I misunderstood the tool's purpose?

I hope you can clarify this confusion of mine.

Thank you in advance!

After upgrading from 1.1.2 to 1.1.3

Describe the bug
After upgrading the library it started to fail with:

Done parsing Play: Run cluster deployment on prepared hypervisors (1) **********
Traceback (most recent call last):
  File "/usr/local/bin/ansible-playbook-grapher", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/cli.py", line 249, in main
    cli.run()
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/cli.py", line 71, in run
    svg_path = renderer.render(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 114, in render
    self._convert_to_graphviz()
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 391, in _convert_to_graphviz
    self.render_node(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 153, in render_node
    self.render_block(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 244, in render_block
    self.render_node(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 161, in render_node
    self.render_role(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 295, in render_role
    role_color = ":".join([c[0] for c in colors])
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 295, in <listcomp>
    role_color = ":".join([c[0] for c in colors])
TypeError: 'NoneType' object is not subscriptable
Error: Process completed with exit code 1.

Versions:
Outputs of :

  • ansible --version
    ansible-5.1.0 ansible-compat-2.2.0 ansible-core-2.12.8
  • ansible-playbook-grapher --version
    Error from 1.1.2(works) to 1.1.3(broken)

[Feature request] Automage releases via Github

Describe the solution you'd like

Currently, I'm releasing manually from my local machine. Ideally, this should be done via Github Actions that generate the release notes and push the package to PyPi.

[Feature request] Multiple playbooks in one graph

Is your feature request related to a problem? Please describe.

I have a folder with playbooks and roles. Some of the roles are referenced in multiple playbooks. I would like to generate a graph with all playbooks and referenced roles. When two playbooks reference the same role, I want to have only one node for that role, and edges from both playbook nodes that reference it to that node.

Describe alternatives you've considered

for playbook in playbooks/*.yaml
do
ansible-playbook-grapher --save-dot-file $playbook
done

And then manually merge the files. You can use grep roles *.dot | sed -e 's@.*playbooks/roles/\(\S\+\)".*@\1@' | sort | uniq --repeated to extract a list of roles that are actually referenced in multiple playbooks.

Additional context
In case that's interesting, these are the playbooks/roles that I want to graph: https://github.com/magma/magma/tree/master/experimental/cloudstrapper

Add support for include_tasks

At this time:

  • the content of task files called by include_tasks is not represented
  • multiple unnamed include_tasks, for example in a block, are represented as a unique task with multiple edges

Nice tool, btw... :-)

include_role within a loop on role name to include generates an error

Describe the bug
When graphing a playbook with a task include_role within a loop on role name, ansible_playbook_grapher raise an execption :

To Reproduce
Assuming following playbook content snippet :

   - name: 'install docker and python addons'
      block:
        - include_role:
            name: '{{ item }}'
          loop:
            - certificates
            - docker
            - python_pip
            - python_docker

ansible_playbook_grapher raises an UndefinedError exception stating item is not defined

Expected behavior
ansible_playbook_grapher runs without exception

Screenshots

Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/ansible/template/__init__.py", line 876, in do_template
    res = j2_concat(rf)
  File "<template>", line 11, in root
  File "/usr/lib/python3.6/site-packages/jinja2/runtime.py", line 635, in _fail_with_undefined_error
    raise self._undefined_exception(hint)
jinja2.exceptions.UndefinedError: 'item' is undefined

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/bin/ansible-playbook-grapher", line 8, in <module>
    sys.exit(main())
  File "/home/..../.local/lib/python3.6/site-packages/ansibleplaybookgrapher/cli.py", line 188, in main
    cli.run()
  File "/home/..../.local/lib/python3.6/site-packages/ansibleplaybookgrapher/cli.py", line 175, in run
    grapher.make_graph()
  File "/home/..../.local/lib/python3.6/site-packages/ansibleplaybookgrapher/grapher.py", line 214, in make_graph
    play_vars=play_vars, node_name_prefix="[task] ")
  File "/home/..../.local/lib/python3.6/site-packages/ansibleplaybookgrapher/grapher.py", line 311, in _include_tasks_in_blocks
    variable_manager=self.variable_manager)
  File "/usr/lib/python3.6/site-packages/ansible/playbook/role_include.py", line 76, in get_block_list
    ri = RoleInclude.load(self._role_name, play=myplay, variable_manager=variable_manager, loader=loader, collection_list=self.collections)
  File "/usr/lib/python3.6/site-packages/ansible/playbook/role/include.py", line 60, in load
    return ri.load_data(data, variable_manager=variable_manager, loader=loader)
  File "/usr/lib/python3.6/site-packages/ansible/playbook/base.py", line 222, in load_data
    ds = self.preprocess_data(ds)
  File "/usr/lib/python3.6/site-packages/ansible/playbook/role/definition.py", line 94, in preprocess_data
    (role_name, role_path) = self._load_role_path(role_name)
  File "/usr/lib/python3.6/site-packages/ansible/playbook/role/definition.py", line 152, in _load_role_path
    role_name = templar.template(role_name)
  File "/usr/lib/python3.6/site-packages/ansible/template/__init__.py", line 617, in template
    disable_lookups=disable_lookups,
  File "/usr/lib/python3.6/site-packages/ansible/template/__init__.py", line 910, in do_template
    raise AnsibleUndefinedVariable(e)
ansible.errors.AnsibleUndefinedVariable: 'item' is undefined

Versions:

  • ansible 2.9.14
    config file = /home/.../ansible.cfg
    configured module search path = ['/home/.../.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
    ansible python module location = /usr/lib/python3.6/site-packages/ansible
    executable location = /usr/bin/ansible
    python version = 3.6.8 (default, Apr 16 2020, 01:36:27) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]

  • ansible-playbook-grapher 0.10.0 (with ansible 2.9.14)

Pb installaling : No such file or directory : directconnect.DescribeVirtualInterfaces_1.json

Hello there,

Trying to install on Windows 10, I have this error on executing : pip install ansible-playbook-grapher :

Collecting ansible-playbook-grapher
Using cached ansible_playbook_grapher-0.10.0-py2.py3-none-any.whl (14 kB)
Collecting lxml==4.5.2
Downloading lxml-4.5.2-cp38-cp38-win32.whl (3.2 MB)
|████████████████████████████████| 3.2 MB 1.1 MB/s
Collecting ansible>=2.8.0
Using cached ansible-2.10.3.tar.gz (28.0 MB)
ERROR: Could not install packages due to an EnvironmentError: [Errno 2] No such file or directory: 'C:\Users\________\AppData\Local\Temp\pip-install-gz3e9eul\ansible\ansible_collections/amazon/aws/tests/unit/modules/placebo_recordings/aws_direct_connect_link_aggregation_group/delete_lag_with_connections_without_force_delete/directconnect.DescribeVirtualInterfaces_1.json'

Any idea, thanks.

Do not follow path

hello,

I just try this tool but I have some issue on path file.

I have the following file mapping (for sample I have deleted some folder):

├── 000-initialize-afs.ym
├── tasks
        ├── include_galaxy.yml
        ├── loop_tasks
                └── _galaxy_resolve_role.yml

When I run : ansible-playbook-grapher 000-initialize-afs.yml

I get this error :

Traceback (most recent call last):
  File "/usr/local/bin/ansible-playbook-grapher", line 10, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/ansibleplaybookgrapher/cli.py", line 84, in main
    cli.run()
  File "/usr/local/lib/python2.7/dist-packages/ansibleplaybookgrapher/cli.py", line 32, in run
    skip_tags=self.options.skip_tags)
  File "/usr/local/lib/python2.7/dist-packages/ansibleplaybookgrapher/grapher.py", line 198, in make_graph
    skip_tags=skip_tags)
  File "/usr/local/lib/python2.7/dist-packages/ansibleplaybookgrapher/grapher.py", line 292, in _include_tasks_in_blocks
    skip_tags=skip_tags)
  File "/usr/local/lib/python2.7/dist-packages/ansibleplaybookgrapher/grapher.py", line 276, in _include_tasks_in_blocks
    data = self.data_loader.load_from_file(include_file)
  File "/usr/local/lib/python2.7/dist-packages/ansible/parsing/dataloader.py", line 88, in load_from_file
    (b_file_data, show_content) = self._get_file_contents(file_name)
  File "/usr/local/lib/python2.7/dist-packages/ansible/parsing/dataloader.py", line 156, in _get_file_contents
    raise AnsibleFileNotFound("Unable to retrieve file contents", file_name=file_name)
ansible.errors.AnsibleFileNotFound: Unable to retrieve file contents
Could not find or access '/home/ubuntu/AFS/142/playbook-athena-foundation-service-core-infrastructure/loop_tasks/_galaxy_resolve_role.yml'

Of course, /home/ubuntu/AFS/142/playbook-athena-foundation-service-core-infrastructure/loop_tasks/_galaxy_resolve_role.yml do not exist. I have this mapping

grep _galaxy 000-initialize-afs.yml
      include_tasks: "tasks/include_galaxy.yml"
 grep _galaxy tasks/include_galaxy.yml
    stat_galaxy_file: none
  register: stat_galaxy_file
      include_tasks: "loop_tasks/_galaxy_resolve_role.yml"
  when: stat_galaxy_file.stat.exists

If I summarize : 000-initialize-afs.yml call tasks/include_galaxy.yml call loop_tasks/_galaxy_resolve_role.yml

[Bug report] Include_role does not create role/task graph instead all tasks are mapped directly to the playbook

Describe the bug
Include_role does not seem to be detected as a "role" for the graph. A flat execution structure of playbook --> tasks is created despite all of the tasks being included in roles

To Reproduce
write a playbook with include_role instead of the roles directive.

Expected behavior
I would expect the same mapping of playbook --> role --> tasks as using the role direective

Versions:
Outputs of :

  • ansible-version: ansible 2.8.5
    config file = /etc/ansible/ansible.cfg
    configured module search path = ['/Users/cvernooy/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
    ansible python module location = /usr/local/Cellar/ansible/2.8.5_1/libexec/lib/python3.7/site-packages/ansible
    executable location = /usr/local/bin/ansible
    python version = 3.7.5 (default, Nov 1 2019, 02:16:32) [Clang 11.0.0 (clang-1100.0.33.8)]

  • ansible-playbook-grapher --version: ansible-playbook-grapher 0.9.1 (with ansible 2.8.4)

Clicking on a node should open the corresponding file

Is your feature request related to a problem? Please describe.
Sometimes when I try to understand a bunch of ansible playbooks, I want to navigate to the playbook that I am looking in the graph. Currently I do it by doing find tool but its very hectic. It would be much better If I click on the node and it should open the file corresponding to that node.

Describe the solution you'd like
It wouldn't be difficult to implement this feature. Just a hint, you could use: graph.attr("node", URL="file name")

Describe alternatives you've considered
I dont know yet, will update soon if have any

[Bug report] ansible-playbook-grapher doesnt work with ansible-core 2.13.1

Describe the bug

When running ansible-playbook-grapher (without arguments), I get the exception

Traceback (most recent call last):
  File "/tmp/tmp.weiU6YpNir/virtualenv/bin/ansible-playbook-grapher", line 33, in <module>
    sys.exit(load_entry_point('ansible-playbook-grapher==1.1.1', 'console_scripts', 'ansible-playbook-grapher')())
  File "/tmp/tmp.weiU6YpNir/virtualenv/lib/python3.9/site-packages/ansibleplaybookgrapher/cli.py", line 249, in main
    cli.run()
  File "/tmp/tmp.weiU6YpNir/virtualenv/lib/python3.9/site-packages/ansibleplaybookgrapher/cli.py", line 52, in run
    super().run()
  File "/tmp/tmp.weiU6YpNir/virtualenv/lib/python3.9/site-packages/ansible/cli/__init__.py", line 109, in run
    self.parse()
  File "/tmp/tmp.weiU6YpNir/virtualenv/lib/python3.9/site-packages/ansible/cli/__init__.py", line 405, in parse
    self.init_parser()
  File "/tmp/tmp.weiU6YpNir/virtualenv/lib/python3.9/site-packages/ansibleplaybookgrapher/cli.py", line 188, in init_parser
    super().init_parser(
  File "/tmp/tmp.weiU6YpNir/virtualenv/lib/python3.9/site-packages/ansible/cli/__init__.py", line 336, in init_parser
    self.parser = opt_help.create_base_parser(self.name, usage=usage, desc=desc, epilog=epilog)
AttributeError: 'PlaybookGrapherCLI' object has no attribute 'name'

To Reproduce

workdir="$(mktemp -d)"
echo "Working in $workdir, you have to clean this up manually"

cd "$workdir"
python -m venv virtualenv
source virtualenv/bin/activate
git clone 'https://github.com/haidaraM/ansible-playbook-grapher'
cd ansible-playbook-grapher
pip install -r requirements.txt
pip install .

ansible-playbook-grapher

Versions:
Outputs of :

  • ansible --version
ansible [core 2.13.1]
  config file = None
  configured module search path = ['/home/jan/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /tmp/tmp.weiU6YpNir/virtualenv/lib/python3.9/site-packages/ansible
  ansible collection location = /home/jan/.ansible/collections:/usr/share/ansible/collections
  executable location = /tmp/tmp.weiU6YpNir/virtualenv/bin/ansible
  python version = 3.9.13 (main, May 17 2022, 14:19:07) [GCC 11.3.0]
  jinja version = 3.1.2
  libyaml = True
  • ansible-playbook-grapher --version
    Doesn't work, leads to above exception

[Bug report] Please bump version of ansible-core

ansible-playbook-grapher) (2.21)
Installing collected packages: ansible-core, ansible-playbook-grapher
  Attempting uninstall: ansible-core
    Found existing installation: ansible-core 2.14.5
    Uninstalling ansible-core-2.14.5:
      Successfully uninstalled ansible-core-2.14.5
ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
ansible 7.5.0 requires ansible-core~=2.14.5, but you have ansible-core 2.12.10 which is incompatible.

Thank you so much!

[Bug report] TypeError: 'str' object is not callable

Describe the bug
When you run the ansible-playbook-grapher some_playbook.yml and the command return a TypeError

To Reproduce
ansible-playbook-grapher some_playbook.yml

Expected behavior
Generate svg file for the playbook

Screenshots
image

Versions:
Outputs of :

  • ansible --version

image

  • ansible-playbook-grapher --version
    ansible-playbook-grapher 0.11.1 (with ansible 2.11.6)
    Additional context
    Using Ubuntu 20.04 LTS WSL

Refactor: make the grapher usable as a library

I wrote most of the grapher almost three years ago in 2017 and lot of things happened since 😄

Currently, the Grapher is tightly coupled to the CLI. This makes it difficult to use it as a library inside another project. Also the Grapher is a little bit complicated: thinking of splitting it. I also want to make the graph customizable by not hardcoding the shapes, layout and make the post processor more extensible.

So this issue is here to track the related changes. The outcome of these changes will be the version v1.0.0 of the grapher?

[Bug report] Relative vars_files

Describe the bug
Var files are not considered relative to playbook's directory.

To Reproduce

- hosts: foo
  vars_files:
    - ../vars/vault.yml

ansible-playbook-grapher playbooks/foo.yml

Expected behavior
Works and takes vaults/variables from vars/

Actual behavior

Traceback (most recent call last):
  File "/home/x/.local/bin/ansible-playbook-grapher", line 8, in <module>
    sys.exit(main())
  File "/home/x/.local/lib/python3.7/site-packages/ansibleplaybookgrapher/cli.py", line 188, in main
    cli.run()
  File "/home/x/.local/lib/python3.7/site-packages/ansibleplaybookgrapher/cli.py", line 175, in run
    grapher.make_graph()
  File "/home/x/.local/lib/python3.7/site-packages/ansibleplaybookgrapher/grapher.py", line 122, in make_graph
    play_vars = self.variable_manager.get_vars(play)
  File "/home/x/.local/lib/python3.7/site-packages/ansible/vars/manager.py", line 363, in get_vars
    raise AnsibleFileNotFound("vars file %s was not found" % vars_file_item)
ansible.errors.AnsibleFileNotFound: vars file ../vars/vault.yml was not found
Could not find file on the Ansible Controller.
If you are using a module and expect the file to exist on the remote, see the remote_src option

Versions:
Outputs of :

  • ansible --version : 2.9.4
  • ansible-playbook-grapher --version : 0.9.3

[Bug report] don't work with collections

Describe the bug
When you call sudo ansible-playbook-grapher playbook_with_something_that_includes_collection.yml and the playbooks uses collections it fails

To Reproduce
sudo ansible-playbook-grapher playbook_with_something_that_includes_collection.yml

Expected behavior
Gerenate the svg file for the playbook

Screenshots
bug-01
bug-02

Versions:
Outputs of :
bug-03

Additional context
Using macOS Big Sur version: 11.2.3

ansible-playbook-grapher fails with different errors in different versions after upgrading from 1.1.2 to 1.2.0

Describe the bug

In this new version ansible-playbook-grapher fails with:

Failure with latest: 1.2.0

ansible-playbook-grapher -t task_gather_facts --skip-tags omit_from_grapher -e kubeinit_cluster_distro=okd -e kubeinit_cluster_distro_role=kubeinit_openshift kubeinit/playbook.yml --include-role-tasks -o docs/src/static/playbook_task_gather_facts --save-dot-file

Parsing playbook kubeinit/playbook.yml
Warning: : No inventory was parsed, only implicit localhost is available
Warning: : Looping on tasks or roles are not supported for the moment. Only the
task having the loop argument will be added to the graph.
Warning: : Could not match supplied host pattern, ignoring:
kubeinit_hypervisors
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/ansible/template/__init__.py", line 1160, in do_template
    res = j2_concat(rf)
  File "<template>", line 12, in root
  File "/usr/lib/python3/dist-packages/jinja2/runtime.py", line 639, in _fail_with_undefined_error
    raise self._undefined_exception(hint)
jinja2.exceptions.UndefinedError: 'hostvars' is undefined

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/bin/ansible-playbook-grapher", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/cli.py", line 269, in main
    cli.run()
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/cli.py", line 61, in run
    grapher.parse(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/graphbuilder.py", line 86, in parse
    playbook_node = parser.parse()
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/parser.py", line 261, in parse
    self._include_tasks_in_blocks(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/parser.py", line 379, in _include_tasks_in_blocks
    block_list, _ = task_or_block.get_block_list(
  File "/usr/local/lib/python3.8/dist-packages/ansible/playbook/role_include.py", line 80, in get_block_list
    ri = RoleInclude.load(self._role_name, play=myplay, variable_manager=variable_manager, loader=loader, collection_list=self.collections)
  File "/usr/local/lib/python3.8/dist-packages/ansible/playbook/role/include.py", line 60, in load
    return ri.load_data(data, variable_manager=variable_manager, loader=loader)
  File "/usr/local/lib/python3.8/dist-packages/ansible/playbook/base.py", line 269, in load_data
    ds = self.preprocess_data(ds)
  File "/usr/local/lib/python3.8/dist-packages/ansible/playbook/role/definition.py", line 95, in preprocess_data
    (role_name, role_path) = self._load_role_path(role_name)
  File "/usr/local/lib/python3.8/dist-packages/ansible/playbook/role/definition.py", line 153, in _load_role_path
    role_name = templar.template(role_name)
  File "/usr/local/lib/python3.8/dist-packages/ansible/template/__init__.py", line 886, in template
    result = self.do_template(
  File "/usr/local/lib/python3.8/dist-packages/ansible/template/__init__.py", line 1199, in do_template
    raise AnsibleUndefinedVariable(e)
ansible.errors.AnsibleUndefinedVariable: 'hostvars' is undefined
Failure with: 1.1.3

ansible-playbook-grapher -t task_gather_facts --skip-tags omit_from_grapher -e kubeinit_cluster_distro=okd -e kubeinit_cluster_distro_role=kubeinit_openshift kubeinit/playbook.yml --include-role-tasks -o docs/src/static/playbook_task_gather_facts --save-dot-file

Warning: : No inventory was parsed, only implicit localhost is available
Parsing Play: Perform initial setup on ansible-controller host (localhost) (1) ***
Warning: : Looping on tasks or roles are not supported for the moment. Only the
task having the loop argument will be added to the graph.
Done parsing Play: Perform initial setup on ansible-controller host (localhost) (1) ***
Warning: : Could not match supplied host pattern, ignoring:
Parsing Play: Gather facts from the cluster hypervisor hosts (0) ***************
kubeinit_hypervisors
Done parsing Play: Gather facts from the cluster hypervisor hosts (0) **********
Parsing Play: Determine facts needed to prepare all hypervisor hosts (1) *******
Done parsing Play: Determine facts needed to prepare all hypervisor hosts (1) ***
Parsing Play: Prepare the infrastructure to deploy service and cluster nodes (0) ***
Done parsing Play: Prepare the infrastructure to deploy service and cluster nodes (0) ***
Parsing Play: Run the deployment on the target infrastructure (OpenStack/libvirt hypervisors) (1) ***
Done parsing Play: Run the deployment on the target infrastructure (OpenStack/libvirt hypervisors) (1) ***

Traceback (most recent call last):
  File "/usr/local/bin/ansible-playbook-grapher", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/cli.py", line 249, in main
    cli.run()
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/cli.py", line 71, in run
    svg_path = renderer.render(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 114, in render
    self._convert_to_graphviz()
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 391, in _convert_to_graphviz
    self.render_node(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 153, in render_node
    self.render_block(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 244, in render_block
    self.render_node(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 161, in render_node
    self.render_role(
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 295, in render_role
    role_color = ":".join([c[0] for c in colors])
  File "/usr/local/lib/python3.8/dist-packages/ansibleplaybookgrapher/renderer.py", line 295, in <listcomp>
    role_color = ":".join([c[0] for c in colors])
TypeError: 'NoneType' object is not subscriptable

Adding a pin works as expected: Kubeinit/kubeinit#702

Do you know what changed that is potentially broken?

Thanks again!
Carlos.

[Bug report] Playbooks with tasks that are the same name get mapped to the same execution

Describe the bug
A clear and concise description of what the bug is.
had a playbook with the same description but did different things in the task and thus it mapped to the same task but it was different
To Reproduce
Steps to reproduce the behavior: playbooks example, command line etc...
create playbook with 2 tasks doing different things but the same name.
Expected behavior
A clear and concise description of what you expected to happen.
would produce 2 tasks seprately denoting what actually is being done (a copy of a file, a shell script, etc)
Screenshots
If applicable, add screenshots to help explain your problem.

Versions:
Outputs of :

  • SC-MKEFFEL-OSX:Collierville_Football_Web mkeffele$ ansible --version ansible 2.8.4 config file = None configured module search path = [u'/Users/mkeffele/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /Library/Python/2.7/site-packages/ansible executable location = /usr/local/bin/ansible python version = 2.7.10 (default, Feb 22 2019, 21:55:15) [GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.37.14)]
  • ansible-playbook-grapher --version
    SC-MKEFFEL-OSX:Collierville_Football_Web mkeffele$ ansible-playbook-grapher --version
    ansible-playbook-grapher 0.9.1 (with ansible 2.8.4)

Additional context
Add any other context about the problem here.

[Feature request] generate mermaid instead of images

Is your feature request related to a problem? Please describe.
No

Describe the solution you'd like
It would be nice to be able to generate mermaid instead of SVG/images, so we could embed the output directly into places that support it , like on GitHub.

quick example:

graph TD
    A[Thievery] -->|Get money| B(Go shopping)
    B --> C{Let me think}
    C -->|One| D[Laptop]
    C -->|Two| E[iPhone]
    C -->|Three| F[fa:fa-car Car]

Make nodes on SVG file collapsable

When running ansible-playbook-grapher --include-role-tasks on a playbook, it would be great if nodes could be collapsable. The graph can become intense and hard to consume.

[Feature request] Variable mapping option

I'm looking to document a large playbook and documenting where variables are declared, and where they're used, has been difficult.

I'd like to see an option to map where variables are defined and where in the playbook they're used. More specifically, if I know I've declared variables in <role-name>/meta/main.yml, I want to tell the grapher to start in <role-name>/meta/main.yml and map to where they are used within that role (or, in other roles).

[Feature request] Add a key to hide plays(tasks) without any role

Is your feature request related to a problem? Please describe.
It would be great if there would be an opportunity to hide plays(tasks) without any role.

Describe the solution you'd like
Please consider adding a key (for example --hide-tasks-without-roles) to ansible-playbook-grapher to hide plays(tasks) without any role.

image

[Feature request] Version Bump :)

Using version ^2.0.0 for ansible-playbook-grapher

Updating dependencies
Resolving dependencies... (1.6s)

Because no versions of ansible match >8.0.0,<8.1.0 || >8.1.0,<8.2.0 || >8.2.0,<8.3.0 || >8.3.0,<8.4.0 || >8.4.0,<9.0.0
 and ansible (8.0.0) depends on ansible-core (>=2.15.0,<2.16.0), ansible (>=8.0.0,<8.1.0 || >8.1.0,<8.2.0 || >8.2.0,<8.3.0 || >8.3.0,<8.4.0 || >8.4.0,<9.0.0) requires ansible-core (>=2.15.0,<2.16.0).
And because ansible (8.1.0) depends on ansible-core (>=2.15.1,<2.16.0)
 and ansible (8.2.0) depends on ansible-core (>=2.15.2,<2.16.0), ansible (>=8.0.0,<8.3.0 || >8.3.0,<8.4.0 || >8.4.0,<9.0.0) requires ansible-core (>=2.15.0,<2.16.0).
And because ansible (8.3.0) depends on ansible-core (>=2.15.3,<2.16.0)
 and ansible (8.4.0) depends on ansible-core (>=2.15.4,<2.16.0), ansible (>=8.0.0,<9.0.0) requires ansible-core (>=2.15.0,<2.16.0).
Because no versions of ansible-playbook-grapher match >2.0.0,<3.0.0
 and ansible-playbook-grapher (2.0.0) depends on ansible-core (>=2.12,<2.15), ansible-playbook-grapher (>=2.0.0,<3.0.0) requires ansible-core (>=2.12,<2.15).
Thus, ansible-playbook-grapher (>=2.0.0,<3.0.0) is incompatible with ansible (>=8.0.0,<9.0.0).
So, because severaln1nes depends on both ansible (^8.0.0) and ansible-playbook-grapher (^2.0.0), version solving failed.

TypeError: Can't instantiate abstract class PlaybookGrapherCLI with abstract methods init_parser, post_process_args

When following the setup guide on MacOs 10.14 and Ubuntu 18.04 I get an abstract methods error. I installed on a new Ubuntu 18.04 machine when testing.

Tried with both Python 2.7 and Python 3.6

vagrant@ubuntu-bionic:/vagrant/provisioning$ ansible-playbook-grapher --help
Traceback (most recent call last):
  File "/home/vagrant/.local/bin/ansible-playbook-grapher", line 11, in <module>
    sys.exit(main())
  File "/home/vagrant/.local/lib/python2.7/site-packages/ansibleplaybookgrapher/cli.py", line 85, in main
    cli = PlaybookGrapherCLI(args)
TypeError: Can't instantiate abstract class PlaybookGrapherCLI with abstract methods init_parser, post_process_args

[Bug report] Fix tasks node name on hover

Describe the bug
When hovering over a node, the node id is displayed instead of it's name

To Reproduce
Graph any playbook and hover over a node.

Expected behavior
The node name should be displayed.

Screenshots
Capture d’écran, le 2020-11-18 à 20 27 18

Versions:
Outputs of :

  • ansible-playbook-grapher --version: ansible-playbook-grapher 0.10.0 (with ansible 2.9.14)

[Feature request] Support for blocks in pre_tasks.

Is your feature request related to a problem? Please describe.
I use blocks in almost every part of a play where a block is allowed, including pre_tasks, but it seems that the grapher is unable to handle those, and generates an exception, making it unusable in most of my complex playbooks :( I wasn't sure if this was a bug, or a feature request, so pardon me if it is the former, and not the latter.

Traceback (most recent call last):
  File "/Users/myUserName/.pyenv/versions/venvGraphAnsible/bin/ansible-playbook-grapher", line 8, in <module>
    sys.exit(main())
  File "/Users/myUserName/.pyenv/versions/3.10.0/envs/venvGraphAnsible/lib/python3.10/site-packages/ansibleplaybookgrapher/cli.py", line 126, in main
    cli.run()
  File "/Users/myUserName/.pyenv/versions/3.10.0/envs/venvGraphAnsible/lib/python3.10/site-packages/ansibleplaybookgrapher/cli.py", line 43, in run
    playbook_node = parser.parse()
  File "/Users/myUserName/.pyenv/versions/3.10.0/envs/venvGraphAnsible/lib/python3.10/site-packages/ansibleplaybookgrapher/parser.py", line 154, in parse
    self._include_tasks_in_blocks(current_play=play, parent_nodes=[play_node], block=pre_task_block,
  File "/Users/myUserName/.pyenv/versions/3.10.0/envs/venvGraphAnsible/lib/python3.10/site-packages/ansibleplaybookgrapher/parser.py", line 245, in _include_tasks_in_blocks
    parent_nodes[-1].add_node(f"{node_type}s", EdgeNode(parent_nodes[-1], role_node,
  File "/Users/myUserName/.pyenv/versions/3.10.0/envs/venvGraphAnsible/lib/python3.10/site-packages/ansibleplaybookgrapher/graph.py", line 58, in add_node
    raise Exception(
Exception: The target composition 'pre_tasks' is unknown. Supported are: ['tasks']

Describe the solution you'd like
The same support as found when using blocks in tasks

Describe alternatives you've considered
N/A

Additional context
Love the library when I can use it, but on my complex plays where I use blocks to keep them clean and apply conditionals on large groups of tasks, where I would love to see the graph to explain to people what is going on, it is a no go.

Argument parsing fails with ansible 2.9.4

Describe the bug
When trying to ask for help it fails while parsing arguments.

ansible-playbook-grapher --help
Traceback (most recent call last):
File "/home/smals-nim/venvs/ansible/bin/ansible-playbook-grapher", line 8, in
sys.exit(main())
File "/home/smals-nim/venvs/ansible/lib/python3.6/site-packages/ansibleplaybookgrapher/cli.py", line 166, in main
cli.parse()
File "/home/smals-nim/venvs/ansible/lib/python3.6/site-packages/ansible/cli/init.py", line 362, in parse
self.init_parser()
File "/home/smals-nim/venvs/ansible/lib/python3.6/site-packages/ansibleplaybookgrapher/cli.py", line 118, in init_parser
_add_my_options(self.parser)
File "/home/smals-nim/venvs/ansible/lib/python3.6/site-packages/ansibleplaybookgrapher/cli.py", line 35, in _add_my_options
parser.add_option('-i', '--inventory', dest='inventory', action="append",
AttributeError: 'ArgumentParser' object has no attribute 'add_option'

Versions:
Outputs of :

  • ansible --version: ansible --version
  • ansible-playbook-grapher --version: doesn't work but pip give me: 0.9.1

Additional context

  • python 3.6 with virtual env

Parse a playbook execution log

It would be nice as a debugging tool if we could parse a playbook execution log and for a given host in the inventory, and colourise the tasks in the graph depending on their execution result (successful, skipped, changed, failed).
This could also be used to hide tasks that don't get run.
Suggested args --execution-log, --hostname and --hide-skipped

IndexError - out of range

Describe the bug
It seems that graphviz has some problems with the generated tree. This is the error message:

Traceback (most recent call last):
  File "/home/me/.local/bin/ansible-playbook-grapher", line 10, in <module>
    sys.exit(main())
  File "/home/me/.local/lib/python2.7/site-packages/ansibleplaybookgrapher/cli.py", line 168, in main
    cli.run()
  File "/home/me/.local/lib/python2.7/site-packages/ansibleplaybookgrapher/cli.py", line 159, in run
    return grapher.post_process_svg()
  File "/home/me/.local/lib/python2.7/site-packages/ansibleplaybookgrapher/grapher.py", line 258, in post_process_svg
    post_processor.post_process(graph_representation=self.graph_representation)
  File "/home/me/.local/lib/python2.7/site-packages/ansibleplaybookgrapher/utils.py", line 196, in post_process
    self._insert_graph_representation(graph_representation)
  File "/home/me/.local/lib/python2.7/site-packages/ansibleplaybookgrapher/utils.py", line 207, in _insert_graph_representation
    element = self.root.xpath("ns:g/*[@id='%s']" % node, namespaces={'ns': SVG_NAMESPACE})[0]
IndexError: list index out of range

To Reproduce
Launching the command to generate a graph~/.local/bin/ansible-playbook-grapher --include-role-tasks -v site.yml

Expected behavior
Get a svg that includes roles' tasks. The command works fine if it is launched without include-role-tasks

Screenshots
If applicable, add screenshots to help explain your problem.

Versions:
ansible-playbook-grapher 0.9.1 (with ansible 2.8.2)

[Bug report] No support for playbooks using `import_tasks`

Any playbook using tasks, does not seem to be supported. For example:

- name: My test task
  import_tasks: test-tasks.yml
  become: true
  tags: [never, testing]

Results in:

ansible.errors.AnsibleParserError: 'import_tasks' is not a valid attribute for a Play

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.