From bcb854540ecb53a8bc1b997af6471c1bad2822bd Mon Sep 17 00:00:00 2001 From: marios Date: Wed, 18 Mar 2015 15:32:26 +0200 Subject: [PATCH] Adds tuskar-delete-roles command The current Tuskar API doesn't cover the role resource lifecycle. For development purposes there is no easy way to delete existing roles that were created with tuskar-load-role and friends. This review adds a tuskar-delete-roles utility that takes a --uuids list of ids to delete. If any of the specified role uuids do not exist, an unknownUUID exception is raised. If any of the specified uuids are in use by an existing plan, a OvercloudRoleInUse exception is raised. In case of either of the above, no roles are deleted and the operation exits. The --dryrun flag can be specified which still goes through the validation above but still does not perform any deletions when that passes. Example invocation: tuskar-delete-roles --config-file ~/tuskar.conf --dryrun --uuids c3b43c3c-e69b-4db7-b0df-3bf2bb8c04cf 5cffe8b6-df60-4cc6-92c6-c8067f0067eb Change-Id: Idb397fd0d6d35b143646d42b171deebc1bce6b36 --- setup.cfg | 1 + tuskar/cmd/delete_roles.py | 47 ++++++++++++++++++ tuskar/storage/delete_roles.py | 71 +++++++++++++++++++++++++++ tuskar/tests/cmd/test_delete_roles.py | 37 ++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 tuskar/cmd/delete_roles.py create mode 100644 tuskar/storage/delete_roles.py create mode 100644 tuskar/tests/cmd/test_delete_roles.py diff --git a/setup.cfg b/setup.cfg index 682d0d98..c210efb4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,6 +27,7 @@ console_scripts = tuskar-dbsync = tuskar.cmd.dbsync:main tuskar-load-roles = tuskar.cmd.load_roles:main tuskar-load-seed = tuskar.cmd.load_seed:main + tuskar-delete-roles = tuskar.cmd.delete_roles:main [build_sphinx] all_files = 1 diff --git a/tuskar/cmd/delete_roles.py b/tuskar/cmd/delete_roles.py new file mode 100644 index 00000000..778f4d8f --- /dev/null +++ b/tuskar/cmd/delete_roles.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# Copyright 2015 Red Hat +# +# 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. + +from __future__ import print_function + +import sys + +from oslo.config import cfg + +from tuskar.common import service +from tuskar.storage.delete_roles import delete_roles + + +def _print_names(message, names): + print("{0}: \n {1}".format(message, '\n '.join(names))) + +cfg.CONF.register_cli_opt(cfg.BoolOpt('dryrun', short='n', default=False)) + +cfg.CONF.register_cli_opt(cfg.ListOpt( + 'uuids', help='List of role uuid to delete')) + + +def main(argv=None): + if argv is None: + argv = sys.argv + + index = argv.index('--uuids') + service.prepare_service(argv[:index]) + roles = argv[index + 1:] + + deleted = delete_roles(roles, noop=cfg.CONF.dryrun) + + if len(deleted): + _print_names("Deleted", deleted) diff --git a/tuskar/storage/delete_roles.py b/tuskar/storage/delete_roles.py new file mode 100644 index 00000000..2102f578 --- /dev/null +++ b/tuskar/storage/delete_roles.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# +# Copyright 2015 Red Hat +# +# 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. + +from __future__ import print_function + +import sys + +from tuskar.common.exception import OvercloudRoleInUse +from tuskar.manager.plan import PlansManager +from tuskar.storage.exceptions import UnknownUUID +from tuskar.storage.stores import DeploymentPlanStore +from tuskar.storage.stores import TemplateStore +from tuskar.templates import parser + + +def _check_roles_exist(role_ids): + store = TemplateStore() + for i in role_ids: + try: + store.retrieve(i) + except UnknownUUID: + sys.stderr.write("No role with id %s " % i) + raise + + +def _check_roles_in_use(role_ids): + manager = PlansManager() + plan_list = manager.list_plans() + plan_store = DeploymentPlanStore() + for plan in plan_list: + db_plan = plan_store.retrieve(plan.uuid) + environment = parser.parse_environment( + db_plan.environment_file.contents + ) + roles_in_use = ( + [role.uuid for role in manager._find_roles(environment)]) + intersection = set(roles_in_use) & set(role_ids) + if intersection: + raise OvercloudRoleInUse(name=", ".join(intersection)) + + +def _delete_role(role_id): + TemplateStore().delete(role_id) + + +def delete_roles(role_ids=None, noop=False): + deleted = [] + # if any of the roles are in use, or invalid, do nothing + _check_roles_in_use(role_ids) + _check_roles_exist(role_ids) + if noop: + role_ids.append("No deletions, dryrun") + return role_ids + else: + for i in role_ids: + _delete_role(i) + deleted.append(i) + return deleted diff --git a/tuskar/tests/cmd/test_delete_roles.py b/tuskar/tests/cmd/test_delete_roles.py new file mode 100644 index 00000000..e6a0d1f6 --- /dev/null +++ b/tuskar/tests/cmd/test_delete_roles.py @@ -0,0 +1,37 @@ +# -*- encoding: utf-8 -*- +# +# 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. + +from mock import call +from mock import patch + +from tuskar.cmd import delete_roles +from tuskar.tests.base import TestCase + + +class DeleteRoleTests(TestCase): + + CMD = """ tuskar-delete-roles --dryrun """ + UUIDS = """ 3 4 5 """ + + @patch('tuskar.storage.stores.TemplateStore.retrieve', return_value="boo") + @patch('tuskar.cmd.delete_roles._print_names') + def test_main(self, mock_print, mock_read): + main_args = "%s --uuids %s" % (self.CMD, self.UUIDS) + expected_res = ['3', '4', '5', 'No deletions, dryrun'] + # test + delete_roles.main(argv=(main_args).split()) + + # verify + self.assertEqual([call('Deleted', expected_res)], + mock_print.call_args_list)