14
14
import fixtures
15
15
import re
16
16
17
+ import collections
17
18
import mock
18
19
import os_resource_classes as orc
19
20
from oslo_config import cfg
20
21
from oslo_log import log as logging
21
22
from oslo_utils import uuidutils
22
23
24
+ from nova .compute import instance_actions
23
25
import nova .conf
24
26
from nova import context
25
27
from nova import objects
26
28
from nova .tests .functional .libvirt import base
29
+ from nova .tests .unit import policy_fixture
27
30
from nova .tests .unit .virt .libvirt import fakelibvirt
28
31
from nova .virt .libvirt import driver as libvirt_driver
29
32
from nova .virt .libvirt import utils as libvirt_utils
@@ -149,10 +152,16 @@ def setUp(self):
149
152
return_value = []))
150
153
self .useFixture (fixtures .MockPatch ('os.rename' ))
151
154
155
+ policy = self .useFixture (policy_fixture .RealPolicyFixture ())
156
+ # Allow non-admins to see instance action events.
157
+ policy .set_rules ({
158
+ 'os_compute_api:os-instance-actions:events' : 'rule:admin_or_owner'
159
+ }, overwrite = False )
160
+
152
161
self .compute1 = self ._start_compute_service (_DEFAULT_HOST )
153
162
154
163
def assert_vgpu_usage_for_compute (self , compute , expected ):
155
- total_usage = 0
164
+ total_usages = collections . defaultdict ( int )
156
165
# We only want to get mdevs that are assigned to instances
157
166
mdevs = compute .driver ._get_all_assigned_mediated_devices ()
158
167
for mdev in mdevs :
@@ -163,10 +172,11 @@ def assert_vgpu_usage_for_compute(self, compute, expected):
163
172
parent_rp_name = compute .host + '_' + parent_name
164
173
parent_rp_uuid = self ._get_provider_uuid_by_name (parent_rp_name )
165
174
parent_usage = self ._get_provider_usages (parent_rp_uuid )
166
- if orc .VGPU in parent_usage :
167
- total_usage += parent_usage [orc .VGPU ]
175
+ if orc .VGPU in parent_usage and parent_rp_name not in total_usages :
176
+ # We only set the total amount if we didn't had it already
177
+ total_usages [parent_rp_name ] = parent_usage [orc .VGPU ]
168
178
self .assertEqual (expected , len (mdevs ))
169
- self .assertEqual (expected , total_usage )
179
+ self .assertEqual (expected , sum ( total_usages [ k ] for k in total_usages ) )
170
180
171
181
def test_create_servers_with_vgpu (self ):
172
182
self ._create_server (
@@ -223,6 +233,60 @@ def test_resize_servers_with_vgpu(self):
223
233
self .assert_vgpu_usage_for_compute (self .compute1 , expected = 0 )
224
234
self .assert_vgpu_usage_for_compute (self .compute2 , expected = 1 )
225
235
236
+ def test_multiple_instance_create (self ):
237
+ body = self ._build_server (
238
+ name = None , image_uuid = '155d900f-4e14-4e4c-a73d-069cbf4541e6' ,
239
+ flavor_id = self .flavor , networks = 'auto' , az = None ,
240
+ host = self .compute1 .host )
241
+ # Asking to multicreate two instances, each of them asking for 1 vGPU
242
+ body ['min_count' ] = 2
243
+ server = self .api .post_server ({'server' : body })
244
+ self ._wait_for_state_change (server , 'ACTIVE' )
245
+
246
+ # Let's verify we created two mediated devices and we have a total of
247
+ # 2 vGPUs
248
+ self .assert_vgpu_usage_for_compute (self .compute1 , expected = 2 )
249
+
250
+ def test_multiple_instance_create_filling_up_capacity (self ):
251
+ # Each pGPU created by fakelibvirt defaults to a capacity of 16 vGPUs.
252
+ # By default, we created a compute service with 2 pGPUs before, so we
253
+ # have a total capacity of 32. In theory, we should be able to find
254
+ # space for two instances asking for 16 vGPUs each.
255
+ extra_spec = {"resources:VGPU" : "16" }
256
+ flavor = self ._create_flavor (extra_spec = extra_spec )
257
+ body = self ._build_server (
258
+ name = None , image_uuid = '155d900f-4e14-4e4c-a73d-069cbf4541e6' ,
259
+ flavor_id = flavor , networks = 'auto' , az = None ,
260
+ host = self .compute1 .host )
261
+ # Asking to multicreate two instances, each of them asking for 8 vGPU
262
+ body ['min_count' ] = 2
263
+ server = self .api .post_server ({'server' : body })
264
+ # But... we fail miserably because of bug #1874664
265
+ # FIXME(sbauza): Change this once we fix the above bug
266
+ server = self ._wait_for_state_change (server , 'ERROR' )
267
+ self .assertIn ('fault' , server )
268
+ self .assertIn ('No valid host' , server ['fault' ]['message' ])
269
+ self .assertEqual ('' , server ['hostId' ])
270
+ # Assert the "create" instance action exists and is failed.
271
+ actions = self .api .get_instance_actions (server ['id' ])
272
+ self .assertEqual (1 , len (actions ), actions )
273
+ action = actions [0 ]
274
+ self .assertEqual (instance_actions .CREATE , action ['action' ])
275
+ self .assertEqual ('Error' , action ['message' ])
276
+ # Get the events. There should be one with an Error result.
277
+ action = self .api .api_get (
278
+ '/servers/%s/os-instance-actions/%s' %
279
+ (server ['id' ], action ['request_id' ])).body ['instanceAction' ]
280
+ events = action ['events' ]
281
+ self .assertEqual (1 , len (events ), events )
282
+ event = events [0 ]
283
+ self .assertEqual ('conductor_schedule_and_build_instances' ,
284
+ event ['event' ])
285
+ self .assertEqual ('Error' , event ['result' ])
286
+ # Normally non-admins cannot see the event traceback but we enabled
287
+ # that via policy in setUp so assert something was recorded.
288
+ self .assertIn ('select_destinations' , event ['traceback' ])
289
+
226
290
227
291
class VGPUMultipleTypesTests (VGPUTestBase ):
228
292
0 commit comments