You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
6.3 KiB
166 lines
6.3 KiB
# Copyright 2021 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. |
|
|
|
from tempest.common import utils |
|
from tempest.common import waiters |
|
from tempest import config |
|
from tempest.lib import decorators |
|
from tempest.lib import exceptions as lib_exc |
|
from tempest.scenario import manager |
|
|
|
CONF = config.CONF |
|
|
|
|
|
class ComputeProjectQuotaTest(manager.ScenarioTest): |
|
"""The test base class for compute unified limits tests. |
|
|
|
Dynamic credentials (unique tenants) are created on a per-class basis, so |
|
we test different quota limits in separate test classes to prevent a quota |
|
limit update in one test class from affecting a test running in another |
|
test class in parallel. |
|
|
|
https://docs.openstack.org/tempest/latest/configuration.html#dynamic-credentials |
|
""" |
|
credentials = ['primary', 'system_admin'] |
|
force_tenant_isolation = True |
|
|
|
@classmethod |
|
def skip_checks(cls): |
|
super(ComputeProjectQuotaTest, cls).skip_checks() |
|
if not CONF.compute_feature_enabled.unified_limits: |
|
raise cls.skipException('Compute unified limits are not enabled.') |
|
|
|
@classmethod |
|
def resource_setup(cls): |
|
super(ComputeProjectQuotaTest, cls).resource_setup() |
|
|
|
# Figure out and record the nova service id |
|
services = cls.os_system_admin.identity_services_v3_client.\ |
|
list_services() |
|
nova_services = [x for x in services['services'] |
|
if x['name'] == 'nova'] |
|
cls.nova_service_id = nova_services[0]['id'] |
|
|
|
# Pre-create quota limits in subclasses and record their IDs so we can |
|
# update them in-place without needing to know which ones have been |
|
# created and in which order. |
|
cls.limit_ids = {} |
|
|
|
@classmethod |
|
def _create_limit(cls, name, value): |
|
return cls.os_system_admin.identity_limits_client.create_limit( |
|
CONF.identity.region, cls.nova_service_id, |
|
cls.servers_client.tenant_id, name, value)['limits'][0]['id'] |
|
|
|
def _update_limit(self, name, value): |
|
self.os_system_admin.identity_limits_client.update_limit( |
|
self.limit_ids[name], value) |
|
|
|
|
|
class ServersQuotaTest(ComputeProjectQuotaTest): |
|
|
|
@classmethod |
|
def resource_setup(cls): |
|
super(ServersQuotaTest, cls).resource_setup() |
|
|
|
try: |
|
cls.limit_ids['servers'] = cls._create_limit( |
|
'servers', 5) |
|
cls.limit_ids['class:VCPU'] = cls._create_limit( |
|
'class:VCPU', 10) |
|
cls.limit_ids['class:MEMORY_MB'] = cls._create_limit( |
|
'class:MEMORY_MB', 25 * 1024) |
|
cls.limit_ids['class:DISK_GB'] = cls._create_limit( |
|
'class:DISK_GB', 10) |
|
except lib_exc.Forbidden: |
|
raise cls.skipException('Target system is not configured with ' |
|
'compute unified limits') |
|
|
|
@decorators.idempotent_id('555d8bbf-d2ed-4e39-858c-4235899402d9') |
|
@utils.services('compute') |
|
def test_server_count_vcpu_memory_disk_quota(self): |
|
# Set a quota on the number of servers for our tenant to one. |
|
self._update_limit('servers', 1) |
|
|
|
# Create one server. |
|
first = self.create_server(name='first') |
|
|
|
# Second server would put us over quota, so expect failure. |
|
# NOTE: In nova, quota exceeded raises 403 Forbidden. |
|
self.assertRaises(lib_exc.Forbidden, |
|
self.create_server, |
|
name='second') |
|
|
|
# Update our limit to two. |
|
self._update_limit('servers', 2) |
|
|
|
# Now the same create should succeed. |
|
second = self.create_server(name='second') |
|
|
|
# Third server would put us over quota, so expect failure. |
|
self.assertRaises(lib_exc.Forbidden, |
|
self.create_server, |
|
name='third') |
|
|
|
# Delete the first server to put us under quota. |
|
self.servers_client.delete_server(first['id']) |
|
waiters.wait_for_server_termination(self.servers_client, first['id']) |
|
|
|
# Now the same create should succeed. |
|
third = self.create_server(name='third') |
|
|
|
# Set the servers limit back to 10 to test other resources. |
|
self._update_limit('servers', 10) |
|
|
|
# Default flavor has: VCPU=1, MEMORY_MB=512, DISK_GB=1 |
|
# We are currently using 2 VCPU, set the limit to 2. |
|
self._update_limit('class:VCPU', 2) |
|
|
|
# Server create should fail as it would go over quota. |
|
self.assertRaises(lib_exc.Forbidden, |
|
self.create_server, |
|
name='fourth') |
|
|
|
# Delete the second server to put us under quota. |
|
self.servers_client.delete_server(second['id']) |
|
waiters.wait_for_server_termination(self.servers_client, second['id']) |
|
|
|
# Same create should now succeed. |
|
fourth = self.create_server(name='fourth') |
|
|
|
# We are currently using 2 DISK_GB. Set limit to 1. |
|
self._update_limit('class:DISK_GB', 1) |
|
|
|
# Server create should fail because we're already over (new) quota. |
|
self.assertRaises(lib_exc.Forbidden, |
|
self.create_server, |
|
name='fifth') |
|
|
|
# Delete the third server. |
|
self.servers_client.delete_server(third['id']) |
|
waiters.wait_for_server_termination(self.servers_client, third['id']) |
|
|
|
# Server create should fail again because it would still put us over |
|
# quota. |
|
self.assertRaises(lib_exc.Forbidden, |
|
self.create_server, |
|
name='fifth') |
|
|
|
# Delete the fourth server. |
|
self.servers_client.delete_server(fourth['id']) |
|
waiters.wait_for_server_termination(self.servers_client, fourth['id']) |
|
|
|
# Server create should succeed now. |
|
self.create_server(name='fifth')
|
|
|