Split user and admin cleanup to 2 separate classes

Partially implements: blueprint benchmark-context-cleanup-refactor
Change-Id: I3ba0deeb5a2793b8c45f6160fe0eda22250a1ece
This commit is contained in:
Aswad Rangnekar 2014-07-04 11:06:01 +05:30 committed by Sergey Skripnick
parent b1ceff67bf
commit 2fb4ba41d5
8 changed files with 269 additions and 165 deletions

View File

@ -0,0 +1,78 @@
# Copyright 2014: Mirantis 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 six
from rally.benchmark.context import base
from rally.benchmark.context.cleanup import utils
from rally.openstack.common.gettextutils import _
from rally.openstack.common import log as logging
from rally import osclients
from rally import utils as rutils
LOG = logging.getLogger(__name__)
class AdminCleanup(base.Context):
"""Context class for admin resource cleanup."""
__ctx_name__ = "admin_cleanup"
__ctx_order__ = 200
__ctx_hidden__ = True
CONFIG_SCHEMA = {
"type": "array",
"$schema": rutils.JSON_SCHEMA,
"items": {
"type": "string",
"enum": ["keystone", "quotas"]
},
"uniqueItems": True
}
def __init__(self, context):
super(AdminCleanup, self).__init__(context)
self.endpoint = None
def _cleanup_resources(self):
client = osclients.Clients(self.endpoint)
cleanup_methods = {
"keystone": (utils.delete_keystone_resources, client.keystone()),
"quotas": (utils.delete_admin_quotas, client,
self.context.get("tenants", [])),
}
for service_name in self.config:
cleanup_method = cleanup_methods[service_name]
method, client = cleanup_method[:2]
try:
method(client, *cleanup_method[2:])
except Exception as e:
LOG.debug("Not all admin resources were cleaned.",
exc_info=sys.exc_info())
LOG.warning(_('Unable to fully cleanup the cloud: %s') %
(six.text_type(e)))
@rutils.log_task_wrapper(LOG.info, _("Enter context: `admin cleanup`"))
def setup(self):
self.endpoint = self.context["admin"]["endpoint"]
@rutils.log_task_wrapper(LOG.info, _("Exit context: `admin cleanup`"))
def cleanup(self):
self._cleanup_resources()

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import functools
import sys
import six
@ -29,11 +28,11 @@ from rally import utils as rutils
LOG = logging.getLogger(__name__)
class ResourceCleaner(base.Context):
"""Context class for resource cleanup (both admin and non-admin)."""
class UserCleanup(base.Context):
"""Context class for user resource cleanup."""
__ctx_name__ = "cleanup"
__ctx_order__ = 200
__ctx_order__ = 201
__ctx_hidden__ = True
CONFIG_SCHEMA = {
@ -42,29 +41,24 @@ class ResourceCleaner(base.Context):
"items": {
"type": "string",
"enum": ["nova", "glance", "cinder",
"quotas", "neutron", "ceilometer", "heat", "sahara"]
"neutron", "ceilometer", "heat", "sahara"]
},
"uniqueItems": True
}
def __init__(self, context):
super(ResourceCleaner, self).__init__(context)
self.admin = []
self.users = []
super(UserCleanup, self).__init__(context)
self.users_endpoints = []
@rutils.log_task_wrapper(LOG.info, _("Cleanup users resources."))
def _cleanup_users_resources(self):
for user in self.users:
def _cleanup_resources(self):
for user in self.users_endpoints:
clients = osclients.Clients(user)
admin_clients = functools.partial(osclients.Clients, self.admin)
tenant_id = clients.keystone().tenant_id
cleanup_methods = {
"nova": (utils.delete_nova_resources, clients.nova),
"glance": (utils.delete_glance_resources, clients.glance,
tenant_id),
"cinder": (utils.delete_cinder_resources, clients.cinder),
"quotas": (utils.delete_quotas, admin_clients,
tenant_id),
"neutron": (utils.delete_neutron_resources, clients.neutron,
tenant_id),
"ceilometer": (utils.delete_ceilometer_resources,
@ -74,39 +68,23 @@ class ResourceCleaner(base.Context):
}
for service_name in self.config:
cleanup_method = cleanup_methods[service_name]
method = cleanup_method[0]
client = cleanup_method[1]()
try:
service = cleanup_methods[service_name]
method = service[0]
client = service[1]()
args = service[2:]
method(client, *args)
method(client, *cleanup_method[2:])
except Exception as e:
LOG.debug("Not all resources were cleaned.",
LOG.debug("Not all user resources were cleaned.",
exc_info=sys.exc_info())
LOG.warning(_('Unable to fully cleanup the cloud: %s') %
(six.text_type(e)))
@rutils.log_task_wrapper(LOG.info, _("Cleanup admin resources."))
def _cleanup_admin_resources(self):
try:
admin = osclients.Clients(self.admin)
utils.delete_keystone_resources(admin.keystone())
except Exception as e:
LOG.debug("Not all resources were cleaned.",
exc_info=sys.exc_info())
LOG.warning(_('Unable to fully cleanup keystone service: %s') %
(six.text_type(e)))
@rutils.log_task_wrapper(LOG.info, _("Enter context: `cleanup`"))
def setup(self):
if "admin" in self.context and self.context["admin"]:
self.admin = self.context["admin"]["endpoint"]
if "users" in self.context and self.context["users"]:
self.users = [u["endpoint"] for u in self.context["users"]]
self.users_endpoints = [u["endpoint"]
for u in self.context.get("users", [])]
@rutils.log_task_wrapper(LOG.info, _("Exit context: `cleanup`"))
def cleanup(self):
if self.users and self.config:
self._cleanup_users_resources()
if self.admin:
self._cleanup_admin_resources()
if self.users_endpoints and self.config:
self._cleanup_resources()

View File

@ -39,6 +39,11 @@ def delete_heat_resources(heat):
delete_stacks(heat)
def delete_admin_quotas(client, tenants):
for tenant in tenants:
delete_quotas(client, tenant["id"])
def delete_keystone_resources(keystone):
keystone = keystone_wrapper.wrap(keystone)
for resource in ["user", "project", "service", "role"]:

View File

@ -20,20 +20,24 @@ from rally.benchmark import validation
class KeystoneBasic(kutils.KeystoneScenario):
@scenario_base.scenario(admin_only=True, context={"cleanup": []})
@scenario_base.scenario(admin_only=True,
context={"admin_cleanup": ["keystone"]})
def create_user(self, name_length=10, **kwargs):
self._user_create(name_length=name_length, **kwargs)
@scenario_base.scenario(admin_only=True, context={"cleanup": []})
@scenario_base.scenario(admin_only=True,
context={"admin_cleanup": ["keystone"]})
def create_delete_user(self, name_length=10, **kwargs):
user = self._user_create(name_length=name_length, **kwargs)
self._resource_delete(user)
@scenario_base.scenario(admin_only=True, context={"cleanup": []})
@scenario_base.scenario(admin_only=True,
context={"admin_cleanup": ["keystone"]})
def create_tenant(self, name_length=10, **kwargs):
self._tenant_create(name_length=name_length, **kwargs)
@scenario_base.scenario(admin_only=True, context={"cleanup": []})
@scenario_base.scenario(admin_only=True,
context={"admin_cleanup": ["keystone"]})
@validation.add(validation.required_parameters(['users_per_tenant']))
def create_tenant_with_users(self, users_per_tenant, name_length=10,
**kwargs):
@ -41,12 +45,14 @@ class KeystoneBasic(kutils.KeystoneScenario):
self._users_create(tenant, users_per_tenant=users_per_tenant,
name_length=name_length)
@scenario_base.scenario(admin_only=True, context={"cleanup": []})
@scenario_base.scenario(admin_only=True,
context={"admin_cleanup": ["keystone"]})
def create_and_list_users(self, name_length=10, **kwargs):
self._user_create(name_length=name_length, **kwargs)
self._list_users()
@scenario_base.scenario(admin_only=True, context={"cleanup": []})
@scenario_base.scenario(admin_only=True,
context={"admin_cleanup": ["keystone"]})
def create_and_list_tenants(self, name_length=10, **kwargs):
self._tenant_create(name_length=name_length, **kwargs)
self._list_tenants()

View File

@ -19,7 +19,8 @@ from rally.benchmark.scenarios.quotas import utils
class Quotas(utils.QuotasScenario):
@scenario_base.scenario(admin_only=True, context={"cleanup": ["quotas"]})
@scenario_base.scenario(admin_only=True,
context={"admin_cleanup": ["quotas"]})
def nova_update(self, max_quota=1024):
"""Tests updating quotas for nova.
@ -28,7 +29,8 @@ class Quotas(utils.QuotasScenario):
tenant_id = self.context()["user"]["tenant_id"]
self._update_quotas('nova', tenant_id, max_quota)
@scenario_base.scenario(admin_only=True, context={"cleanup": ["quotas"]})
@scenario_base.scenario(admin_only=True,
context={"admin_cleanup": ["quotas"]})
def nova_update_and_delete(self, max_quota=1024):
"""Tests updating and deleting quotas for nova.
@ -39,7 +41,8 @@ class Quotas(utils.QuotasScenario):
self._update_quotas('nova', tenant_id, max_quota)
self._delete_quotas('nova', tenant_id)
@scenario_base.scenario(admin_only=True, context={"cleanup": ["quotas"]})
@scenario_base.scenario(admin_only=True,
context={"admin_cleanup": ["quotas"]})
def cinder_update(self, max_quota=1024):
"""Tests updating quotas for cinder.

View File

@ -0,0 +1,59 @@
# Copyright 2014: Mirantis 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 mock
from rally.benchmark.context.cleanup import admin_cleanup
from tests import fakes
from tests import test
BASE = "rally.benchmark.context.cleanup.admin_cleanup"
class AdminCleanupTestCase(test.TestCase):
def test_with_statement(self):
fake_admin_ctx = fakes.FakeUserContext({}).context
fake_admin_ctx["config"] = {"admin_cleanup": ["keystone"]}
admin_cleaner = admin_cleanup.AdminCleanup(fake_admin_ctx)
admin_cleaner.setup()
admin_cleaner._cleanup_resources = mock.MagicMock()
with admin_cleaner as cleaner:
self.assertEqual(admin_cleaner, cleaner)
admin_cleaner._cleanup_resources.assert_called_once_with()
@mock.patch("%s.osclients.Clients" % BASE)
@mock.patch("%s.utils.delete_keystone_resources" % BASE)
def test_cleaner_admin(self, mock_del_keystone, mock_clients):
context = {
"task": mock.MagicMock(),
"config": {"admin_cleanup": ["keystone"]},
"admin": {"endpoint": mock.MagicMock()},
}
res_cleaner = admin_cleanup.AdminCleanup(context)
fake_keystone = mock.MagicMock()
mock_clients.return_value.keystone.return_value = fake_keystone
with res_cleaner:
res_cleaner.setup()
mock_clients.assert_called_once_with(context["admin"]["endpoint"])
mock_clients.return_value.keystone.assert_called_with()
mock_del_keystone.assert_called_once_with(fake_keystone)

View File

@ -1,117 +0,0 @@
# Copyright 2014: Mirantis 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 mock
from rally.benchmark.context.cleanup import cleanup as cleanup_ctx
from tests import fakes
from tests import test
BASE = "rally.benchmark.context.cleanup.cleanup"
class ResourceCleanerTestCase(test.TestCase):
def test_with_statement_no_user_no_admin(self):
context = {
"task": mock.MagicMock(),
"admin": None,
"users": [],
"tenants": [],
}
resource_cleaner = cleanup_ctx.ResourceCleaner(context)
with resource_cleaner:
resource_cleaner.setup()
def test_with_statement(self):
fake_user_ctx = fakes.FakeUserContext({}).context
fake_user_ctx["config"] = {"cleanup": ["nova"]}
res_cleaner = cleanup_ctx.ResourceCleaner(fake_user_ctx)
res_cleaner.setup()
res_cleaner._cleanup_users_resources = mock.MagicMock()
res_cleaner._cleanup_admin_resources = mock.MagicMock()
with res_cleaner as cleaner:
self.assertEqual(res_cleaner, cleaner)
res_cleaner._cleanup_users_resources.assert_called_once_with()
res_cleaner._cleanup_admin_resources.assert_called_once_with()
@mock.patch("%s.osclients.Clients" % BASE)
@mock.patch("%s.utils.delete_keystone_resources" % BASE)
def test_cleaner_admin(self, mock_del_keystone, mock_clients):
context = {
"task": mock.MagicMock(),
"config": {"cleanup": ["cinder", "nova"]},
"admin": {"endpoint": mock.MagicMock()},
}
res_cleaner = cleanup_ctx.ResourceCleaner(context)
mock_clients.return_value.keystone.return_value = 'keystone'
with res_cleaner:
res_cleaner.setup()
mock_clients.assert_called_once_with(context["admin"]["endpoint"])
mock_clients.return_value.keystone.assert_called_once_with()
mock_del_keystone.assert_called_once_with('keystone')
@mock.patch("%s.osclients.Clients" % BASE)
@mock.patch("%s.utils.delete_nova_resources" % BASE)
@mock.patch("%s.utils.delete_glance_resources" % BASE)
@mock.patch("%s.utils.delete_cinder_resources" % BASE)
@mock.patch("%s.utils.delete_neutron_resources" % BASE)
def test_cleaner_users_resources(self,
mock_del_neutron,
mock_del_cinder,
mock_del_glance,
mock_del_nova,
mock_clients):
context = {
"task": mock.MagicMock(),
"users": [{"endpoint": mock.MagicMock()},
{"endpoint": mock.MagicMock()}],
"config": {"cleanup": ["cinder", "nova", "glance", "neutron"]},
"tenants": [mock.MagicMock()]
}
res_cleaner = cleanup_ctx.ResourceCleaner(context)
with res_cleaner:
res_cleaner.setup()
expected = [mock.call(context["users"][0]["endpoint"]),
mock.call(context["users"][1]["endpoint"])]
mock_clients.assert_has_calls(expected, any_order=True)
self.assertEqual(mock_del_nova.call_count, 2)
self.assertEqual(mock_del_glance.call_count, 2)
self.assertEqual(mock_del_cinder.call_count, 2)
self.assertEqual(mock_del_neutron.call_count, 2)
@mock.patch("%s.ResourceCleaner._cleanup_users_resources" % BASE)
def test_cleaner_users_default_behavior(self, mock_cleanup):
context = {
"task": mock.MagicMock(),
"users": [{"endpoint": mock.MagicMock()},
{"endpoint": mock.MagicMock()}],
}
res_cleaner = cleanup_ctx.ResourceCleaner(context)
with res_cleaner:
res_cleaner.setup()
self.assertEqual(mock_cleanup.call_count, 0)

View File

@ -0,0 +1,92 @@
# Copyright 2014: Mirantis 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 mock
from rally.benchmark.context.cleanup import user_cleanup
from tests import fakes
from tests import test
BASE = "rally.benchmark.context.cleanup.user_cleanup"
class UserCleanupTestCase(test.TestCase):
def test_with_statement_no_user(self):
context = {
"task": mock.MagicMock(),
"admin": mock.MagicMock(),
"users": [],
"tenants": [],
}
user_cleaner = user_cleanup.UserCleanup(context)
with user_cleaner:
user_cleaner.setup()
def test_with_statement(self):
fake_user_ctx = fakes.FakeUserContext({}).context
fake_user_ctx["config"] = {"cleanup": ["nova"]}
user_cleaner = user_cleanup.UserCleanup(fake_user_ctx)
user_cleaner.setup()
user_cleaner._cleanup_resources = mock.MagicMock()
with user_cleaner as cleaner:
self.assertEqual(user_cleaner, cleaner)
user_cleaner._cleanup_resources.assert_called_once_with()
@mock.patch("%s.osclients.Clients" % BASE)
@mock.patch("%s.utils.delete_nova_resources" % BASE)
@mock.patch("%s.utils.delete_glance_resources" % BASE)
@mock.patch("%s.utils.delete_cinder_resources" % BASE)
@mock.patch("%s.utils.delete_neutron_resources" % BASE)
def test_cleaner_resources(self, mock_del_neutron, mock_del_cinder,
mock_del_glance, mock_del_nova, mock_clients):
context = {
"task": mock.MagicMock(),
"users": [{"endpoint": mock.MagicMock()},
{"endpoint": mock.MagicMock()}],
"config": {"cleanup": ["cinder", "nova", "glance", "neutron"]},
"tenants": [mock.MagicMock()]
}
user_cleaner = user_cleanup.UserCleanup(context)
with user_cleaner:
user_cleaner.setup()
expected = [mock.call(context["users"][0]["endpoint"]),
mock.call(context["users"][1]["endpoint"])]
mock_clients.assert_has_calls(expected, any_order=True)
self.assertEqual(mock_del_nova.call_count, 2)
self.assertEqual(mock_del_glance.call_count, 2)
self.assertEqual(mock_del_cinder.call_count, 2)
self.assertEqual(mock_del_neutron.call_count, 2)
@mock.patch("%s.UserCleanup._cleanup_resources" % BASE)
def test_cleaner_default_behavior(self, mock_cleanup):
context = {
"task": mock.MagicMock(),
"users": [{"endpoint": mock.MagicMock()},
{"endpoint": mock.MagicMock()}],
}
user_cleaner = user_cleanup.UserCleanup(context)
with user_cleaner:
user_cleaner.setup()
self.assertEqual(mock_cleanup.call_count, 0)