Make quotas context cleanup lazy
*) Clean up service quotas only if they were changed. *) Code clean up in setup() and cleanup() to avoid copy paste *) Use append instead of extend in quotas tests *) Init clients as well lazy *) Add functional tests for quotas *) Fix names of nova quotas *) Fix don't break everything if you are not able to delete quota Closes-bug: #1329907 Closes-bug: #1329795 Closes-bug: #1329379 Change-Id: I2ea781f08a731500bfff85e4c25e9786108b8b70
This commit is contained in:
parent
29eb4fb5a5
commit
e973ced371
@ -1,4 +1,39 @@
|
||||
---
|
||||
Dummy.dummy:
|
||||
-
|
||||
args:
|
||||
sleep: 0.01
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 1
|
||||
concurrency: 1
|
||||
context:
|
||||
users:
|
||||
tenants: 5
|
||||
users_per_tenant: 5
|
||||
quotas:
|
||||
nova:
|
||||
instances: 200
|
||||
cores: 200
|
||||
ram: -1
|
||||
metadata_items: -1
|
||||
injected_files: -1
|
||||
injected_file_content_bytes: -1
|
||||
injected_file_path_bytes: -1
|
||||
key_pairs: 500
|
||||
cinder:
|
||||
gigabytes: -1
|
||||
snapshots: -1
|
||||
volumes: -1
|
||||
neutron:
|
||||
network: -1
|
||||
subnet: -1
|
||||
port: 200
|
||||
router: 300
|
||||
floatingip: -1
|
||||
security_group: -1
|
||||
security_group_rule: -1
|
||||
|
||||
NeutronNetworks.create_and_list_networks:
|
||||
-
|
||||
args:
|
||||
|
@ -101,7 +101,7 @@
|
||||
Dummy.dummy:
|
||||
-
|
||||
args:
|
||||
sleep: 5
|
||||
sleep: 0.25
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 20
|
||||
@ -110,6 +110,35 @@
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
||||
-
|
||||
args:
|
||||
sleep: 0.01
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 1
|
||||
concurrency: 1
|
||||
context:
|
||||
users:
|
||||
tenants: 5
|
||||
users_per_tenant: 5
|
||||
quotas:
|
||||
nova:
|
||||
instances: 200
|
||||
cores: 200
|
||||
ram: -1
|
||||
floating_ips: 200
|
||||
fixed_ips: 200
|
||||
metadata_items: -1
|
||||
injected_files: -1
|
||||
injected_file_content_bytes: -1
|
||||
injected_file_path_bytes: -1
|
||||
key_pairs: 500
|
||||
security_groups: 400
|
||||
security_group_rules: 600
|
||||
cinder:
|
||||
gigabytes: -1
|
||||
snapshots: -1
|
||||
volumes: -1
|
||||
|
||||
Dummy.dummy_exception:
|
||||
-
|
||||
|
@ -42,54 +42,54 @@ class NovaQuotas(object):
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"floating-ips": {
|
||||
"floating_ips": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"fixed-ips": {
|
||||
"fixed_ips": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"metadata-items": {
|
||||
"metadata_items": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"injected-files": {
|
||||
"injected_files": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"injected-file-content-bytes": {
|
||||
"injected_file_content_bytes": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"injected-file-path-bytes": {
|
||||
"injected_file_path_bytes": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"key-pairs": {
|
||||
"key_pairs": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"security-groups": {
|
||||
"security_groups": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"security-group-rules": {
|
||||
"security_group_rules": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
def __init__(self, clients):
|
||||
self.clients = clients
|
||||
|
||||
def update(self, tenant_id, **kwargs):
|
||||
self.client.quotas.update(tenant_id, **kwargs)
|
||||
self.clients.nova().quotas.update(tenant_id, **kwargs)
|
||||
|
||||
def delete(self, tenant_id):
|
||||
# Reset quotas to defaults and tag database objects as deleted
|
||||
self.client.quotas.delete(tenant_id)
|
||||
self.clients.nova().quotas.delete(tenant_id)
|
||||
|
||||
|
||||
class CinderQuotas(object):
|
||||
@ -114,11 +114,11 @@ class CinderQuotas(object):
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
def __init__(self, clients):
|
||||
self.clients = clients
|
||||
|
||||
def update(self, tenant_id, **kwargs):
|
||||
self.client.quotas.update(tenant_id, **kwargs)
|
||||
self.clients.cinder().quotas.update(tenant_id, **kwargs)
|
||||
|
||||
def delete(self, tenant_id):
|
||||
# Currently, no method to delete quotas available in cinder client:
|
||||
@ -153,27 +153,27 @@ class NeutronQuotas(object):
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"security-group": {
|
||||
"security_group": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
},
|
||||
"security-group-rule": {
|
||||
"security_group_rule": {
|
||||
"type": "integer",
|
||||
"minimum": -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
def __init__(self, clients):
|
||||
self.clients = clients
|
||||
|
||||
def update(self, tenant_id, **kwargs):
|
||||
body = {"quota": kwargs}
|
||||
self.client.update_quota(tenant_id, body=body)
|
||||
self.clients.neutron().update_quota(tenant_id, body=body)
|
||||
|
||||
def delete(self, tenant_id):
|
||||
# Reset quotas to defaults and tag database objects as deleted
|
||||
self.client.delete_quota(tenant_id)
|
||||
self.clients.neutron().delete_quota(tenant_id)
|
||||
|
||||
|
||||
class Quotas(base.Context):
|
||||
@ -197,29 +197,34 @@ class Quotas(base.Context):
|
||||
def __init__(self, context):
|
||||
super(Quotas, self).__init__(context)
|
||||
self.clients = osclients.Clients(context["admin"]["endpoint"])
|
||||
self.nova_quotas = NovaQuotas(self.clients.nova())
|
||||
self.cinder_quotas = CinderQuotas(self.clients.cinder())
|
||||
self.neutron_quotas = NeutronQuotas(self.clients.neutron())
|
||||
|
||||
self.manager = {
|
||||
"nova": NovaQuotas(self.clients),
|
||||
"cinder": CinderQuotas(self.clients),
|
||||
"neutron": NeutronQuotas(self.clients)
|
||||
}
|
||||
|
||||
def _service_has_quotas(self, service):
|
||||
return len(self.config.get(service, {})) > 0
|
||||
|
||||
@utils.log_task_wrapper(LOG.info, _("Enter context: `quotas`"))
|
||||
def setup(self):
|
||||
for tenant in self.context["tenants"]:
|
||||
if "nova" in self.config and len(self.config["nova"]) > 0:
|
||||
self.nova_quotas.update(tenant["id"],
|
||||
**self.config["nova"])
|
||||
|
||||
if "cinder" in self.config and len(self.config["cinder"]) > 0:
|
||||
self.cinder_quotas.update(tenant["id"],
|
||||
**self.config["cinder"])
|
||||
|
||||
if "neutron" in self.config and len(self.config["neutron"]) > 0:
|
||||
self.neutron_quotas.update(tenant["id"],
|
||||
**self.config["neutron"])
|
||||
for service in self.manager:
|
||||
if self._service_has_quotas(service):
|
||||
self.manager[service].update(tenant["id"],
|
||||
**self.config[service])
|
||||
|
||||
@utils.log_task_wrapper(LOG.info, _("Exit context: `quotas`"))
|
||||
def cleanup(self):
|
||||
for tenant in self.context["tenants"]:
|
||||
# Always cleanup quotas before deleting a tenant
|
||||
self.nova_quotas.delete(tenant["id"])
|
||||
self.cinder_quotas.delete(tenant["id"])
|
||||
self.neutron_quotas.delete(tenant["id"])
|
||||
for service in self.manager:
|
||||
if self._service_has_quotas(service):
|
||||
for tenant in self.context["tenants"]:
|
||||
try:
|
||||
self.manager[service].delete(tenant["id"])
|
||||
except Exception as e:
|
||||
LOG.warning("Failed to remove quotas for tenant "
|
||||
"%(tenant_id)s in service %(service)s "
|
||||
"\n reason: %(exc)s"
|
||||
% {"tenant_id": tenant["id"],
|
||||
"service": service, "exc": e})
|
||||
|
@ -24,7 +24,7 @@ from tests import test
|
||||
|
||||
class NovaQuotasTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients.nova")
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients")
|
||||
def test_update(self, client_mock):
|
||||
nova_quotas = quotas.NovaQuotas(client_mock)
|
||||
tenant_id = mock.MagicMock()
|
||||
@ -32,31 +32,31 @@ class NovaQuotasTestCase(test.TestCase):
|
||||
"instances": 10,
|
||||
"cores": 100,
|
||||
"ram": 100000,
|
||||
"floating-ips": 100,
|
||||
"fixed-ips": 10000,
|
||||
"metadata-items": 5,
|
||||
"injected-files": 5,
|
||||
"injected-file-content-bytes": 2048,
|
||||
"injected-file-path-bytes": 1024,
|
||||
"key-pairs": 50,
|
||||
"security-groups": 50,
|
||||
"security-group-rules": 50
|
||||
"floating_ips": 100,
|
||||
"fixed_ips": 10000,
|
||||
"metadata_items": 5,
|
||||
"injected_files": 5,
|
||||
"injected_file_content_bytes": 2048,
|
||||
"injected_file_path_bytes": 1024,
|
||||
"key_pairs": 50,
|
||||
"security_groups": 50,
|
||||
"security_group_rules": 50
|
||||
}
|
||||
nova_quotas.update(tenant_id, **quotas_values)
|
||||
client_mock.quotas.update.assert_called_once_with(tenant_id,
|
||||
**quotas_values)
|
||||
client_mock.nova().quotas.update.assert_called_once_with(
|
||||
tenant_id, **quotas_values)
|
||||
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients.nova")
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients")
|
||||
def test_delete(self, client_mock):
|
||||
nova_quotas = quotas.NovaQuotas(client_mock)
|
||||
tenant_id = mock.MagicMock()
|
||||
nova_quotas.delete(tenant_id)
|
||||
client_mock.quotas.delete.assert_called_once_with(tenant_id)
|
||||
client_mock.nova().quotas.delete.assert_called_once_with(tenant_id)
|
||||
|
||||
|
||||
class CinderQuotasTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients.cinder")
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients")
|
||||
def test_update(self, client_mock):
|
||||
cinder_quotas = quotas.CinderQuotas(client_mock)
|
||||
tenant_id = mock.MagicMock()
|
||||
@ -66,10 +66,10 @@ class CinderQuotasTestCase(test.TestCase):
|
||||
"gigabytes": 1000
|
||||
}
|
||||
cinder_quotas.update(tenant_id, **quotas_values)
|
||||
client_mock.quotas.update.assert_called_once_with(tenant_id,
|
||||
**quotas_values)
|
||||
client_mock.cinder().quotas.update.assert_called_once_with(
|
||||
tenant_id, **quotas_values)
|
||||
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients.cinder")
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients")
|
||||
def test_delete(self, client_mock):
|
||||
pass
|
||||
# Currently, no method to delete quotas available in cinder client:
|
||||
@ -82,7 +82,7 @@ class CinderQuotasTestCase(test.TestCase):
|
||||
|
||||
class NeutronQuotasTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients.neutron")
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients")
|
||||
def test_update(self, client_mock):
|
||||
neutron_quotas = quotas.NeutronQuotas(client_mock)
|
||||
tenant_id = mock.MagicMock()
|
||||
@ -92,19 +92,20 @@ class NeutronQuotasTestCase(test.TestCase):
|
||||
"port": 100,
|
||||
"router": 20,
|
||||
"floatingip": 100,
|
||||
"security-group": 100,
|
||||
"security-group-rule": 100
|
||||
"security_group": 100,
|
||||
"security_group_rule": 100
|
||||
}
|
||||
neutron_quotas.update(tenant_id, **quotas_values)
|
||||
body = {"quota": quotas_values}
|
||||
client_mock.update_quota.assert_called_once_with(tenant_id, body=body)
|
||||
client_mock.neutron().update_quota.assert_called_once_with(tenant_id,
|
||||
body=body)
|
||||
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients.neutron")
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients")
|
||||
def test_delete(self, client_mock):
|
||||
neutron_quotas = quotas.NeutronQuotas(client_mock)
|
||||
tenant_id = mock.MagicMock()
|
||||
neutron_quotas.delete(tenant_id)
|
||||
client_mock.delete_quota.assert_called_once_with(tenant_id)
|
||||
client_mock.neutron().delete_quota.assert_called_once_with(tenant_id)
|
||||
|
||||
|
||||
class QuotasTestCase(test.TestCase):
|
||||
@ -135,15 +136,15 @@ class QuotasTestCase(test.TestCase):
|
||||
"instances": self.unlimited,
|
||||
"cores": self.unlimited,
|
||||
"ram": self.unlimited,
|
||||
"floating-ips": self.unlimited,
|
||||
"fixed-ips": self.unlimited,
|
||||
"metadata-items": self.unlimited,
|
||||
"injected-files": self.unlimited,
|
||||
"injected-file-content-bytes": self.unlimited,
|
||||
"injected-file-path-bytes": self.unlimited,
|
||||
"key-pairs": self.unlimited,
|
||||
"security-groups": self.unlimited,
|
||||
"security-group-rules": self.unlimited
|
||||
"floating_ips": self.unlimited,
|
||||
"fixed_ips": self.unlimited,
|
||||
"metadata_items": self.unlimited,
|
||||
"injected_files": self.unlimited,
|
||||
"injected_file_content_bytes": self.unlimited,
|
||||
"injected_file_path_bytes": self.unlimited,
|
||||
"key_pairs": self.unlimited,
|
||||
"security_groups": self.unlimited,
|
||||
"security_group_rules": self.unlimited
|
||||
},
|
||||
"neutron": {
|
||||
"network": self.unlimited,
|
||||
@ -151,8 +152,8 @@ class QuotasTestCase(test.TestCase):
|
||||
"port": self.unlimited,
|
||||
"router": self.unlimited,
|
||||
"floatingip": self.unlimited,
|
||||
"security-group": self.unlimited,
|
||||
"security-group-rule": self.unlimited
|
||||
"security_group": self.unlimited,
|
||||
"security_group_rule": self.unlimited
|
||||
}
|
||||
}
|
||||
for service in ctx["config"]["quotas"]:
|
||||
@ -234,15 +235,15 @@ class QuotasTestCase(test.TestCase):
|
||||
quotas_ctx.setup()
|
||||
expected_setup_calls = []
|
||||
for tenant in tenants:
|
||||
expected_setup_calls.extend([mock.call()
|
||||
.update(tenant["id"],
|
||||
**cinder_quotas)])
|
||||
expected_setup_calls.append(mock.call()
|
||||
.update(tenant["id"],
|
||||
**cinder_quotas))
|
||||
mock_quotas.assert_has_calls(expected_setup_calls, any_order=True)
|
||||
mock_quotas.reset_mock()
|
||||
|
||||
expected_cleanup_calls = []
|
||||
for tenant in tenants:
|
||||
expected_cleanup_calls.extend([mock.call().delete(tenant["id"])])
|
||||
expected_cleanup_calls.append(mock.call().delete(tenant["id"]))
|
||||
mock_quotas.assert_has_calls(expected_cleanup_calls, any_order=True)
|
||||
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients")
|
||||
@ -257,13 +258,13 @@ class QuotasTestCase(test.TestCase):
|
||||
"ram": self.unlimited,
|
||||
"floating-ips": self.unlimited,
|
||||
"fixed-ips": self.unlimited,
|
||||
"metadata-items": self.unlimited,
|
||||
"injected-files": self.unlimited,
|
||||
"injected-file-content-bytes": self.unlimited,
|
||||
"injected-file-path-bytes": self.unlimited,
|
||||
"key-pairs": self.unlimited,
|
||||
"security-groups": self.unlimited,
|
||||
"security-group-rules": self.unlimited,
|
||||
"metadata_items": self.unlimited,
|
||||
"injected_files": self.unlimited,
|
||||
"injected_file_content_bytes": self.unlimited,
|
||||
"injected_file_path_bytes": self.unlimited,
|
||||
"key_pairs": self.unlimited,
|
||||
"security_groups": self.unlimited,
|
||||
"security_group_rules": self.unlimited,
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,15 +274,15 @@ class QuotasTestCase(test.TestCase):
|
||||
quotas_ctx.setup()
|
||||
expected_setup_calls = []
|
||||
for tenant in tenants:
|
||||
expected_setup_calls.extend([mock.call()
|
||||
.update(tenant["id"],
|
||||
**nova_quotas)])
|
||||
expected_setup_calls.append(mock.call()
|
||||
.update(tenant["id"],
|
||||
**nova_quotas))
|
||||
mock_quotas.assert_has_calls(expected_setup_calls, any_order=True)
|
||||
mock_quotas.reset_mock()
|
||||
|
||||
expected_cleanup_calls = []
|
||||
for tenant in tenants:
|
||||
expected_cleanup_calls.extend([mock.call().delete(tenant["id"])])
|
||||
expected_cleanup_calls.append(mock.call().delete(tenant["id"]))
|
||||
mock_quotas.assert_has_calls(expected_cleanup_calls, any_order=True)
|
||||
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients")
|
||||
@ -296,8 +297,8 @@ class QuotasTestCase(test.TestCase):
|
||||
"port": self.unlimited,
|
||||
"router": self.unlimited,
|
||||
"floatingip": self.unlimited,
|
||||
"security-group": self.unlimited,
|
||||
"security-group-rule": self.unlimited
|
||||
"security_group": self.unlimited,
|
||||
"security_group_rule": self.unlimited
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,15 +308,15 @@ class QuotasTestCase(test.TestCase):
|
||||
quotas_ctx.setup()
|
||||
expected_setup_calls = []
|
||||
for tenant in tenants:
|
||||
expected_setup_calls.extend([mock.call()
|
||||
.update(tenant["id"],
|
||||
**neutron_quotas)])
|
||||
expected_setup_calls.append(mock.call()
|
||||
.update(tenant["id"],
|
||||
**neutron_quotas))
|
||||
mock_quotas.assert_has_calls(expected_setup_calls, any_order=True)
|
||||
mock_quotas.reset_mock()
|
||||
|
||||
expected_cleanup_calls = []
|
||||
for tenant in tenants:
|
||||
expected_cleanup_calls.extend([mock.call().delete(tenant["id"])])
|
||||
expected_cleanup_calls.append(mock.call().delete(tenant["id"]))
|
||||
mock_quotas.assert_has_calls(expected_cleanup_calls, any_order=True)
|
||||
|
||||
@mock.patch("rally.benchmark.context.quotas.osclients.Clients")
|
||||
@ -333,17 +334,21 @@ class QuotasTestCase(test.TestCase):
|
||||
self.assertFalse(mock_cinder_quotas.update.called)
|
||||
self.assertFalse(mock_nova_quotas.update.called)
|
||||
self.assertFalse(mock_neutron_quotas.update.called)
|
||||
mock_nova_quotas.reset_mock()
|
||||
mock_cinder_quotas.reset_mock()
|
||||
mock_neutron_quotas.reset_mock()
|
||||
|
||||
tenants = ctx["tenants"]
|
||||
expected_cleanup_calls = []
|
||||
for tenant in tenants:
|
||||
expected_cleanup_calls.extend([mock.call().delete(tenant["id"])])
|
||||
mock_nova_quotas.assert_has_calls(expected_cleanup_calls,
|
||||
any_order=True)
|
||||
mock_cinder_quotas.assert_has_calls(expected_cleanup_calls,
|
||||
any_order=True)
|
||||
mock_neutron_quotas.assert_has_calls(expected_cleanup_calls,
|
||||
any_order=True)
|
||||
self.assertFalse(mock_cinder_quotas.delete.called)
|
||||
self.assertFalse(mock_nova_quotas.delete.called)
|
||||
self.assertFalse(mock_neutron_quotas.delete.called)
|
||||
|
||||
@mock.patch("rally.benchmark.context.quotas.NovaQuotas")
|
||||
def test_exception_during_cleanup(self, mock_nova_quotas):
|
||||
|
||||
mock_nova_quotas.delete.side_effect = Exception("boom")
|
||||
|
||||
ctx = copy.deepcopy(self.context)
|
||||
ctx["config"]["quotas"] = {"nova": {"cpu": 1}}
|
||||
|
||||
# NOTE(boris-42): ensure that cleanup didn't raise exceptions.
|
||||
quotas.Quotas(ctx).cleanup()
|
||||
|
||||
self.assertEqual(mock_nova_quotas().delete.call_count,
|
||||
len(self.context["tenants"]))
|
||||
|
Loading…
x
Reference in New Issue
Block a user