Skip to content

Commit

Permalink
fix #18: New CLI compatible with ansible 2.8
Browse files Browse the repository at this point in the history
This change is needed because of ansible/ansible#50069.
The new CLI in this PR should be used in the future when we drop support
for Ansible < 2.8
  • Loading branch information
Mohamed El Mouctar HAIDARA committed Jun 6, 2019
1 parent 1ac40f8 commit 90e6047
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 31 deletions.
115 changes: 97 additions & 18 deletions ansibleplaybookgrapher/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,46 @@
from ansible.cli import CLI
from ansible.errors import AnsibleOptionsError
from ansible.release import __version__ as ansible_version
from ansible.utils.display import Display
from packaging import version

from ansibleplaybookgrapher import __prog__, __version__
from ansibleplaybookgrapher.grapher import Grapher

display = Display()
# We need to know if we are using ansible 2.8 because the CLI has been refactored in
# https://github.com/ansible/ansible/pull/50069
IS_ANSIBLE_2_8_X = version.parse(ansible_version) >= version.parse("2.8")


def get_cli_class():
"""
Utility function to return the class to use as CLI depending on Ansible version
:return:
"""
if IS_ANSIBLE_2_8_X:
return PlaybookGrapherCLI28
else:
return PlaybookGrapherCLI


def _add_my_options(parser):
"""
Add some of my options to the parser
:param parser:
:return:
"""
parser.add_option('-i', '--inventory', dest='inventory', action="append",
help="specify inventory host path (default=[%s]) or comma separated host list. ")

parser.add_option("--include-role-tasks", dest="include_role_tasks", action='store_true', default=False,
help="Include the tasks of the role in the graph.")

parser.add_option("-s", "--save-dot-file", dest="save_dot_file", action='store_true', default=False,
help="Save the dot file used to generate the graph.")

parser.add_option("-o", "--ouput-file-name", dest='output_filename',
help="Output filename without the '.svg' extension. Default: <playbook>.svg")

parser.version = "%s %s (with ansible %s)" % (__prog__, __version__, ansible_version)


class PlaybookGrapherCLI(CLI):
Expand Down Expand Up @@ -49,19 +83,7 @@ def parse(self):
desc="Make graph from your Playbook.",
)

parser.add_option('-i', '--inventory', dest='inventory', action="append",
help="specify inventory host path (default=[%s]) or comma separated host list. ")

parser.add_option("--include-role-tasks", dest="include_role_tasks", action='store_true', default=False,
help="Include the tasks of the role in the graph.")

parser.add_option("-s", "--save-dot-file", dest="save_dot_file", action='store_true', default=False,
help="Save the dot file used to generate the graph.")

parser.add_option("-o", "--ouput-file-name", dest='output_filename',
help="Output filename without the '.svg' extension. Default: <playbook>.svg")

parser.version = "%s %s (with ansible %s)" % (__prog__, __version__, ansible_version)
_add_my_options(parser)

self.parser = parser

Expand All @@ -73,16 +95,73 @@ def parse(self):
if len(self.args) > 1:
raise AnsibleOptionsError("You must specify only one playbook file to graph.")

display.verbosity = self.options.verbosity

if self.options.output_filename is None:
# use the playbook name (without the extension) as output filename
self.options.output_filename = os.path.splitext(ntpath.basename(self.args[0]))[0]


class PlaybookGrapherCLI28(CLI):
"""
Dedicated playbook for Ansible 2.8 and above.
FIXME: Use this class as the main CLI when we drop support for ansible < 2.8
"""

def __init__(self, args, callback=None):
super(PlaybookGrapherCLI28, self).__init__(args=args, callback=callback)
# we keep the old options as instance attribute for backward compatibility for the grapher
# Ansible 2.8 has removed it and use a global context instead
self.options = None

def init_parser(self, usage="", desc=None, epilog=None):
super(PlaybookGrapherCLI28, self).init_parser(usage="%s [options] playbook.yml" % __prog__,
desc="Make graph from your Playbook.", epilog=epilog)
_add_my_options(self.parser)

from ansible.cli.arguments import optparse_helpers as opt_help

opt_help.add_subset_options(self.parser)
opt_help.add_vault_options(self.parser)
opt_help.add_runtask_options(self.parser)

def post_process_args(self, options, args):
options, args = super(PlaybookGrapherCLI28, self).post_process_args(options, args)

if len(args) == 0:
raise AnsibleOptionsError("You must specify a playbook file to graph.")

if len(args) > 1:
raise AnsibleOptionsError("You must specify only one playbook file to graph.")

# init the options
self.options = options
self.options.playbook_filename = args[0]

if self.options.output_filename is None:
# use the playbook name (without the extension) as output filename
self.options.output_filename = os.path.splitext(ntpath.basename(self.options.playbook_filename))[0]

return options, args

def run(self):
super(PlaybookGrapherCLI28, self).run()

playbook = self.options.args[0]

loader, inventory, variable_manager = self._play_prereqs()

grapher = Grapher(data_loader=loader, inventory_manager=inventory, variable_manager=variable_manager,
playbook_filename=playbook, options=self.options)

grapher.make_graph()

grapher.render_graph()

return grapher.post_process_svg()


def main(args=None):
args = args or sys.argv
cli = PlaybookGrapherCLI(args)
cli = get_cli_class()(args)

cli.parse()

Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ansible>=2.7.0
graphviz==0.10.1
colour==0.1.5
lxml==4.2.5
lxml==4.2.5
packaging==19.0
20 changes: 10 additions & 10 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from ansible.release import __version__ as ansible_version

from ansibleplaybookgrapher import __prog__, __version__
from ansibleplaybookgrapher.cli import PlaybookGrapherCLI
from ansibleplaybookgrapher.cli import get_cli_class


@pytest.mark.parametrize("help_option", ['-h', '--help'])
Expand All @@ -16,7 +16,7 @@ def test_cli_help(help_option, capfd):
"""
args = [__prog__, help_option]

cli = PlaybookGrapherCLI(args)
cli = get_cli_class()(args)

with pytest.raises(SystemExit) as exception_info:
cli.parse()
Expand All @@ -31,7 +31,7 @@ def test_cli_version(capfd):
Test version printing
:return:
"""
cli = PlaybookGrapherCLI([__prog__, '--version'])
cli = get_cli_class()([__prog__, '--version'])
with pytest.raises(SystemExit) as exception_info:
cli.parse()

Expand All @@ -51,7 +51,7 @@ def test_cli_save_dot_file(save_dot_file_option, expected):
"""
args = [__prog__] + save_dot_file_option + ['playbook.yml']

cli = PlaybookGrapherCLI(args)
cli = get_cli_class()(args)

cli.parse()

Expand All @@ -71,7 +71,7 @@ def test_cli_output_filename(output_filename_option, expected):
"""
args = [__prog__] + output_filename_option + ['playbook.yml']

cli = PlaybookGrapherCLI(args)
cli = get_cli_class()(args)

cli.parse()

Expand All @@ -90,7 +90,7 @@ def test_cli_include_role_tasks(include_role_tasks_option, expected):

args = [__prog__] + include_role_tasks_option + ['playboook.yml']

cli = PlaybookGrapherCLI(args)
cli = get_cli_class()(args)

cli.parse()

Expand All @@ -111,7 +111,7 @@ def test_cli_tags(tags_option, expected):
"""
args = [__prog__] + tags_option + ['playbook.yml']

cli = PlaybookGrapherCLI(args)
cli = get_cli_class()(args)

cli.parse()

Expand All @@ -134,7 +134,7 @@ def test_skip_tags(skip_tags_option, expected):
"""
args = [__prog__] + skip_tags_option + ['playbook.yml']

cli = PlaybookGrapherCLI(args)
cli = get_cli_class()(args)

cli.parse()

Expand All @@ -150,7 +150,7 @@ def test_cli_no_playbook():
"""
args = [__prog__]

cli = PlaybookGrapherCLI(args)
cli = get_cli_class()(args)

with pytest.raises(AnsibleOptionsError) as exception_info:
cli.parse()
Expand All @@ -165,7 +165,7 @@ def test_cli_multiple_playbooks():
"""
args = [__prog__, 'playbook1.yml', 'playbook2.yml']

cli = PlaybookGrapherCLI(args)
cli = get_cli_class()(args)

with pytest.raises(AnsibleOptionsError) as exception_info:
cli.parse()
Expand Down
4 changes: 2 additions & 2 deletions tests/test_grapher.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pyquery import PyQuery

from ansibleplaybookgrapher import __prog__
from ansibleplaybookgrapher.cli import PlaybookGrapherCLI
from ansibleplaybookgrapher.cli import get_cli_class
from tests import FIXTURES_DIR


Expand Down Expand Up @@ -32,7 +32,7 @@ def run_grapher(playbook_path, output_filename=None, additional_args=None):

args.append(playbook_path)

cli = PlaybookGrapherCLI(args)
cli = get_cli_class()(args)

cli.parse()

Expand Down

0 comments on commit 90e6047

Please sign in to comment.