blob: eda6d6fb8cb0f19db2193806aba1bc8d155abc7a [file] [log] [blame]
melanie wittbadb24c2021-08-12 01:09:39 +00001# Copyright 2021 Red Hat, Inc.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
melanie wittbadb24c2021-08-12 01:09:39 +000016from tempest.common import utils
17from tempest.common import waiters
18from tempest import config
19from tempest.lib import decorators
20from tempest.lib import exceptions as lib_exc
21from tempest.scenario import manager
22
23CONF = config.CONF
24
25
melanie wittbadb24c2021-08-12 01:09:39 +000026class ComputeProjectQuotaTest(manager.ScenarioTest):
27 """The test base class for compute unified limits tests.
28
29 Dynamic credentials (unique tenants) are created on a per-class basis, so
30 we test different quota limits in separate test classes to prevent a quota
31 limit update in one test class from affecting a test running in another
32 test class in parallel.
33
34 https://docs.openstack.org/tempest/latest/configuration.html#dynamic-credentials
35 """
36 credentials = ['primary', 'system_admin']
37 force_tenant_isolation = True
38
39 @classmethod
Benny Kopilova8149612022-03-17 11:47:41 +020040 def skip_checks(cls):
41 super(ComputeProjectQuotaTest, cls).skip_checks()
42 if not CONF.compute_feature_enabled.unified_limits:
43 raise cls.skipException('Compute unified limits are not enabled.')
44
45 @classmethod
melanie wittbadb24c2021-08-12 01:09:39 +000046 def resource_setup(cls):
47 super(ComputeProjectQuotaTest, cls).resource_setup()
48
49 # Figure out and record the nova service id
50 services = cls.os_system_admin.identity_services_v3_client.\
51 list_services()
52 nova_services = [x for x in services['services']
53 if x['name'] == 'nova']
54 cls.nova_service_id = nova_services[0]['id']
55
56 # Pre-create quota limits in subclasses and record their IDs so we can
57 # update them in-place without needing to know which ones have been
58 # created and in which order.
59 cls.limit_ids = {}
60
61 @classmethod
62 def _create_limit(cls, name, value):
63 return cls.os_system_admin.identity_limits_client.create_limit(
64 CONF.identity.region, cls.nova_service_id,
65 cls.servers_client.tenant_id, name, value)['limits'][0]['id']
66
67 def _update_limit(self, name, value):
68 self.os_system_admin.identity_limits_client.update_limit(
69 self.limit_ids[name], value)
70
71
melanie wittbadb24c2021-08-12 01:09:39 +000072class ServersQuotaTest(ComputeProjectQuotaTest):
73
74 @classmethod
75 def resource_setup(cls):
76 super(ServersQuotaTest, cls).resource_setup()
77
78 try:
79 cls.limit_ids['servers'] = cls._create_limit(
80 'servers', 5)
81 cls.limit_ids['class:VCPU'] = cls._create_limit(
82 'class:VCPU', 10)
83 cls.limit_ids['class:MEMORY_MB'] = cls._create_limit(
84 'class:MEMORY_MB', 25 * 1024)
85 cls.limit_ids['class:DISK_GB'] = cls._create_limit(
86 'class:DISK_GB', 10)
87 except lib_exc.Forbidden:
88 raise cls.skipException('Target system is not configured with '
89 'compute unified limits')
90
91 @decorators.idempotent_id('555d8bbf-d2ed-4e39-858c-4235899402d9')
92 @utils.services('compute')
93 def test_server_count_vcpu_memory_disk_quota(self):
94 # Set a quota on the number of servers for our tenant to one.
95 self._update_limit('servers', 1)
96
97 # Create one server.
98 first = self.create_server(name='first')
99
100 # Second server would put us over quota, so expect failure.
101 # NOTE: In nova, quota exceeded raises 403 Forbidden.
102 self.assertRaises(lib_exc.Forbidden,
103 self.create_server,
104 name='second')
105
106 # Update our limit to two.
107 self._update_limit('servers', 2)
108
109 # Now the same create should succeed.
110 second = self.create_server(name='second')
111
112 # Third server would put us over quota, so expect failure.
113 self.assertRaises(lib_exc.Forbidden,
114 self.create_server,
115 name='third')
116
117 # Delete the first server to put us under quota.
118 self.servers_client.delete_server(first['id'])
119 waiters.wait_for_server_termination(self.servers_client, first['id'])
120
121 # Now the same create should succeed.
122 third = self.create_server(name='third')
123
124 # Set the servers limit back to 10 to test other resources.
125 self._update_limit('servers', 10)
126
127 # Default flavor has: VCPU=1, MEMORY_MB=512, DISK_GB=1
128 # We are currently using 2 VCPU, set the limit to 2.
129 self._update_limit('class:VCPU', 2)
130
131 # Server create should fail as it would go over quota.
132 self.assertRaises(lib_exc.Forbidden,
133 self.create_server,
134 name='fourth')
135
136 # Delete the second server to put us under quota.
137 self.servers_client.delete_server(second['id'])
138 waiters.wait_for_server_termination(self.servers_client, second['id'])
139
140 # Same create should now succeed.
141 fourth = self.create_server(name='fourth')
142
143 # We are currently using 2 DISK_GB. Set limit to 1.
144 self._update_limit('class:DISK_GB', 1)
145
146 # Server create should fail because we're already over (new) quota.
147 self.assertRaises(lib_exc.Forbidden,
148 self.create_server,
149 name='fifth')
150
151 # Delete the third server.
152 self.servers_client.delete_server(third['id'])
153 waiters.wait_for_server_termination(self.servers_client, third['id'])
154
155 # Server create should fail again because it would still put us over
156 # quota.
157 self.assertRaises(lib_exc.Forbidden,
158 self.create_server,
159 name='fifth')
160
161 # Delete the fourth server.
162 self.servers_client.delete_server(fourth['id'])
163 waiters.wait_for_server_termination(self.servers_client, fourth['id'])
164
165 # Server create should succeed now.
166 self.create_server(name='fifth')