From ecaab85f68f6909338e34edbb6d5d83c48871532 Mon Sep 17 00:00:00 2001 From: David Moreau-Simard Date: Wed, 11 May 2016 17:26:10 -0400 Subject: [PATCH] First, minimal implementation of cli commands for each model --- ara/cli/__init__.py | 0 ara/cli/host.py | 60 ++++++++++++++++++++++++++++++++++++++++++ ara/cli/play.py | 60 ++++++++++++++++++++++++++++++++++++++++++ ara/cli/playbook.py | 60 ++++++++++++++++++++++++++++++++++++++++++ ara/cli/result.py | 61 +++++++++++++++++++++++++++++++++++++++++++ ara/cli/stats.py | 61 +++++++++++++++++++++++++++++++++++++++++++ ara/cli/task.py | 61 +++++++++++++++++++++++++++++++++++++++++++ ara/shell.py | 63 +++++++++++++++++++++++++++++++++++++++++++++ ara/utils.py | 16 ++++++++++++ requirements.txt | 1 + setup.cfg | 18 +++++++++++++ 11 files changed, 461 insertions(+) create mode 100644 ara/cli/__init__.py create mode 100644 ara/cli/host.py create mode 100644 ara/cli/play.py create mode 100644 ara/cli/playbook.py create mode 100644 ara/cli/result.py create mode 100644 ara/cli/stats.py create mode 100644 ara/cli/task.py create mode 100644 ara/shell.py diff --git a/ara/cli/__init__.py b/ara/cli/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ara/cli/host.py b/ara/cli/host.py new file mode 100644 index 00000000..82183184 --- /dev/null +++ b/ara/cli/host.py @@ -0,0 +1,60 @@ +# Copyright Red Hat, Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import logging +import six + +from cliff.lister import Lister +from cliff.show import ShowOne +from ara import app, db, models, utils + + +class HostList(Lister): + """Returns a list of hosts""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(HostList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + hosts = models.Host.query.all() + + columns = ('id', 'name') + return (columns, + (utils.get_object_properties(host, columns) + for host in hosts)) + + +class HostShow(ShowOne): + """Show details of a host""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(HostShow, self).get_parser(prog_name) + parser.add_argument( + 'host_id', + metavar='', + help='Host to show', + ) + return parser + + def take_action(self, parsed_args): + host = models.Host.query.get(parsed_args.host_id) + + if hasattr(host, '_sa_instance_state'): + delattr(host, '_sa_instance_state') + + return zip(*sorted(six.iteritems(host.__dict__))) diff --git a/ara/cli/play.py b/ara/cli/play.py new file mode 100644 index 00000000..fb9879d4 --- /dev/null +++ b/ara/cli/play.py @@ -0,0 +1,60 @@ +# Copyright Red Hat, Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import logging +import six + +from cliff.lister import Lister +from cliff.show import ShowOne +from ara import app, db, models, utils + + +class PlayList(Lister): + """Returns a list of plays""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(PlayList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + plays = models.Play.query.all() + + columns = ('id', 'name', 'time start', 'time end') + return (columns, + (utils.get_object_properties(play, columns) + for play in plays)) + + +class PlayShow(ShowOne): + """Show details of a play""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(PlayShow, self).get_parser(prog_name) + parser.add_argument( + 'play_id', + metavar='', + help='Play to show', + ) + return parser + + def take_action(self, parsed_args): + play = models.Play.query.get(parsed_args.play_id) + + if hasattr(play, '_sa_instance_state'): + delattr(play, '_sa_instance_state') + + return zip(*sorted(six.iteritems(play.__dict__))) diff --git a/ara/cli/playbook.py b/ara/cli/playbook.py new file mode 100644 index 00000000..fec1deee --- /dev/null +++ b/ara/cli/playbook.py @@ -0,0 +1,60 @@ +# Copyright Red Hat, Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import logging +import six + +from cliff.lister import Lister +from cliff.show import ShowOne +from ara import app, db, models, utils + + +class PlaybookList(Lister): + """Returns a list of playbooks""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(PlaybookList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + playbooks = models.Playbook.query.all() + + columns = ('id', 'path', 'time start', 'time end') + return (columns, + (utils.get_object_properties(playbook, columns) + for playbook in playbooks)) + + +class PlaybookShow(ShowOne): + """Show details of a playbook""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(PlaybookShow, self).get_parser(prog_name) + parser.add_argument( + 'playbook_id', + metavar='', + help='Playbook to show', + ) + return parser + + def take_action(self, parsed_args): + playbook = models.Playbook.query.get(parsed_args.playbook_id) + + if hasattr(playbook, '_sa_instance_state'): + delattr(playbook, '_sa_instance_state') + + return zip(*sorted(six.iteritems(playbook.__dict__))) diff --git a/ara/cli/result.py b/ara/cli/result.py new file mode 100644 index 00000000..de82b708 --- /dev/null +++ b/ara/cli/result.py @@ -0,0 +1,61 @@ +# Copyright Red Hat, Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import logging +import six + +from cliff.lister import Lister +from cliff.show import ShowOne +from ara import app, db, models, utils + + +class ResultList(Lister): + """Returns a list of results""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(ResultList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + results = models.TaskResult.query.all() + + columns = ('id', 'task id', 'host id', 'changed', 'failed', 'skipped', + 'unreachable', 'ignore errors', 'time start', 'time end') + return (columns, + (utils.get_object_properties(result, columns) + for result in results)) + + +class ResultShow(ShowOne): + """Show details of a result""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(ResultShow, self).get_parser(prog_name) + parser.add_argument( + 'result_id', + metavar='', + help='Result to show', + ) + return parser + + def take_action(self, parsed_args): + result = models.TaskResult.query.get(parsed_args.result_id) + + if hasattr(result, '_sa_instance_state'): + delattr(result, '_sa_instance_state') + + return zip(*sorted(six.iteritems(result.__dict__))) diff --git a/ara/cli/stats.py b/ara/cli/stats.py new file mode 100644 index 00000000..e118890a --- /dev/null +++ b/ara/cli/stats.py @@ -0,0 +1,61 @@ +# Copyright Red Hat, Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import logging +import six + +from cliff.lister import Lister +from cliff.show import ShowOne +from ara import app, db, models, utils + + +class StatsList(Lister): + """Returns a list of statistics""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(StatsList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + stats = models.Stats.query.all() + + columns = ('id', 'playbook id', 'host id', 'changed', 'failures', + 'ok', 'skipped', 'unreachable') + return (columns, + (utils.get_object_properties(stat, columns) + for stat in stats)) + + +class StatsShow(ShowOne): + """Show details of a statistic""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(StatsShow, self).get_parser(prog_name) + parser.add_argument( + 'stats_id', + metavar='', + help='Statistic to show', + ) + return parser + + def take_action(self, parsed_args): + stats = models.Stats.query.get(parsed_args.stats_id) + + if hasattr(stats, '_sa_instance_state'): + delattr(stats, '_sa_instance_state') + + return zip(*sorted(six.iteritems(stats.__dict__))) diff --git a/ara/cli/task.py b/ara/cli/task.py new file mode 100644 index 00000000..9c0abef4 --- /dev/null +++ b/ara/cli/task.py @@ -0,0 +1,61 @@ +# Copyright Red Hat, Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import logging +import six + +from cliff.lister import Lister +from cliff.show import ShowOne +from ara import app, db, models, utils + + +class TaskList(Lister): + """Returns a list of tasks""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(TaskList, self).get_parser(prog_name) + return parser + + def take_action(self, parsed_args): + tasks = models.Task.query.all() + + columns = ('id', 'playbook id', 'play id', 'name', 'action', 'path', + 'lineno', 'is handler', 'time start', 'time end') + return (columns, + (utils.get_object_properties(task, columns) + for task in tasks)) + + +class TaskShow(ShowOne): + """Show details of a task""" + log = logging.getLogger(__name__) + + def get_parser(self, prog_name): + parser = super(TaskShow, self).get_parser(prog_name) + parser.add_argument( + 'task_id', + metavar='', + help='Task to show', + ) + return parser + + def take_action(self, parsed_args): + task = models.Task.query.get(parsed_args.task_id) + + if hasattr(task, '_sa_instance_state'): + delattr(task, '_sa_instance_state') + + return zip(*sorted(six.iteritems(task.__dict__))) diff --git a/ara/shell.py b/ara/shell.py new file mode 100644 index 00000000..85273457 --- /dev/null +++ b/ara/shell.py @@ -0,0 +1,63 @@ +# Copyright 2016 Red Hat, Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import sys +import os + +from ara import __version__ +from ara.defaults import * # NOQA +from cliff.app import App +from cliff.commandmanager import CommandManager + + +class AraCli(App): + """ + A CLI client to query ARA databases + """ + def __init__(self): + super(AraCli, self).__init__( + description='A CLI client to query ARA databases', + version=__version__, + command_manager=CommandManager('ara.cli'), + deferred_help=True, + ) + + def build_option_parser(self, description, version): + parser = super(AraCli, self).build_option_parser(description, version) + + # Global arguments + # < None right now > + + return parser + + def initialize_app(self, argv): + self.LOG.debug('initialize_app') + + def prepare_to_run_command(self, cmd): + self.LOG.debug('prepare_to_run_command %s', cmd.__class__.__name__) + + def clean_up(self, cmd, result, err): + self.LOG.debug('clean_up %s', cmd.__class__.__name__) + if err: + self.LOG.debug('got an error: %s', err) + + +def main(argv=sys.argv[1:]): + aracli = AraCli() + return aracli.run(argv) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/ara/utils.py b/ara/utils.py index a6fe8d90..4c64ca7b 100644 --- a/ara/utils.py +++ b/ara/utils.py @@ -110,3 +110,19 @@ def get_stats_for_playbooks(playbook_uuids, **kwargs): data[uuid] = models.Stats.query.filter_by(playbook_uuid=uuid, **kwargs) return data + + +def get_object_properties(item, fields): + """Return a tuple containing the item properties. + :param item: a single object resource + :param fields: tuple of strings with the desired field names + :param formatters: dictionary mapping field names to callables + to format the values + """ + row = [] + + for field in fields: + field_name = field.lower().replace(' ', '_') + data = getattr(item, field_name) if hasattr(item, field_name) else '' + row.append(data) + return tuple(row) diff --git a/requirements.txt b/requirements.txt index 7eec6cdb..007b221f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ Flask Flask-SQLAlchemy pbr>=1.6 decorator +cliff \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index e6cc634d..1cc394e0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -39,3 +39,21 @@ universal = 1 [pbr] skip_authors = True skip_changelog = True + +[entry_points] +console_scripts = + ara = ara.shell:main + +ara.cli = + playbook list = ara.cli.playbook:PlaybookList + playbook show = ara.cli.playbook:PlaybookShow + task list = ara.cli.task:TaskList + task show = ara.cli.task:TaskShow + play list = ara.cli.play:PlayList + play show = ara.cli.play:PlayShow + result list = ara.cli.result:ResultList + result show = ara.cli.result:ResultShow + host list = ara.cli.host:HostList + host show = ara.cli.host:HostShow + stats list = ara.cli.stats:StatsList + stats show = ara.cli.stats:StatsShow