1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2010 OpenStack LLC
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6
# not use this file except in compliance with the License. You may obtain
7
# a copy of the License at
9
# http://www.apache.org/licenses/LICENSE-2.0
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
# License for the specific language governing permissions and limitations
27
from xml.etree import ElementTree
28
from xml.dom import minidom
30
from nova import context
32
from nova import exception
33
from nova import flags
34
from nova import log as logging
36
from nova import utils
37
from nova.api.ec2 import cloud
38
from nova.compute import instance_types
39
from nova.compute import power_state
40
from nova.compute import utils as compute_utils
41
from nova.compute import vm_states
42
from nova.virt import images
43
from nova.virt import driver
44
from nova.virt import firewall as base_firewall
45
from nova.virt.libvirt import connection
46
from nova.virt.libvirt import firewall
47
from nova.virt.libvirt import volume
48
from nova.volume import driver as volume_driver
49
from nova.virt.libvirt import utils as libvirt_utils
50
from nova.tests import fake_network
51
from nova.tests import fake_libvirt_utils
56
connection.libvirt = libvirt
62
LOG = logging.getLogger(__name__)
64
_fake_network_info = fake_network.fake_get_instance_nw_info
65
_fake_stub_out_get_nw_info = fake_network.stub_out_nw_api_get_instance_nw_info
66
_ipv4_like = fake_network.ipv4_like
69
def _concurrency(wait, done, target):
74
class FakeVirDomainSnapshot(object):
76
def __init__(self, dom=None):
79
def delete(self, flags):
83
class FakeVirtDomain(object):
85
def __init__(self, fake_xml=None):
87
self._fake_dom_xml = fake_xml
89
self._fake_dom_xml = """
93
<source file='filename'/>
100
return "fake-domain %s" % self
103
return [power_state.RUNNING, None, None, None, None]
108
def managedSave(self, *args):
111
def createWithFlags(self, launch_flags):
114
def XMLDesc(self, *args):
115
return self._fake_dom_xml
118
class LibvirtVolumeTestCase(test.TestCase):
121
super(LibvirtVolumeTestCase, self).setUp()
124
def fake_execute(*cmd, **kwargs):
125
self.executes.append(cmd)
128
self.stubs.Set(utils, 'execute', fake_execute)
130
class FakeLibvirtConnection(object):
131
def __init__(self, hyperv="QEMU"):
134
def get_hypervisor_type(self):
137
def get_all_block_devices(self):
140
self.fake_conn = FakeLibvirtConnection()
143
'initiator': 'fake_initiator'
146
def test_libvirt_iscsi_driver(self):
147
# NOTE(vish) exists is to make driver assume connecting worked
148
self.stubs.Set(os.path, 'exists', lambda x: True)
149
vol_driver = volume_driver.ISCSIDriver()
150
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
151
location = '10.0.2.15:3260'
152
name = 'volume-00000001'
153
iqn = 'iqn.2010-10.org.openstack:%s' % name
156
'provider_auth': None,
157
'provider_location': '%s,fake %s' % (location, iqn)}
158
connection_info = vol_driver.initialize_connection(vol, self.connr)
160
xml = libvirt_driver.connect_volume(connection_info, mount_device)
161
tree = ElementTree.fromstring(xml)
162
dev_str = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-0' % (location, iqn)
163
self.assertEqual(tree.get('type'), 'block')
164
self.assertEqual(tree.find('./source').get('dev'), dev_str)
165
libvirt_driver.disconnect_volume(connection_info, mount_device)
166
connection_info = vol_driver.terminate_connection(vol, self.connr)
167
expected_commands = [('iscsiadm', '-m', 'node', '-T', iqn,
169
('iscsiadm', '-m', 'node', '-T', iqn,
170
'-p', location, '--login'),
171
('iscsiadm', '-m', 'node', '-T', iqn,
172
'-p', location, '--op', 'update',
173
'-n', 'node.startup', '-v', 'automatic'),
174
('iscsiadm', '-m', 'node', '-T', iqn,
175
'-p', location, '--op', 'update',
176
'-n', 'node.startup', '-v', 'manual'),
177
('iscsiadm', '-m', 'node', '-T', iqn,
178
'-p', location, '--logout'),
179
('iscsiadm', '-m', 'node', '-T', iqn,
180
'-p', location, '--op', 'delete')]
181
self.assertEqual(self.executes, expected_commands)
183
def test_libvirt_iscsi_driver_still_in_use(self):
184
# NOTE(vish) exists is to make driver assume connecting worked
185
self.stubs.Set(os.path, 'exists', lambda x: True)
186
vol_driver = volume_driver.ISCSIDriver()
187
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
188
location = '10.0.2.15:3260'
189
name = 'volume-00000001'
190
iqn = 'iqn.2010-10.org.openstack:%s' % name
191
devs = ['/dev/disk/by-path/ip-%s-iscsi-%s-lun-1' % (location, iqn)]
192
self.stubs.Set(self.fake_conn, 'get_all_block_devices', lambda: devs)
195
'provider_auth': None,
196
'provider_location': '%s,fake %s' % (location, iqn)}
197
connection_info = vol_driver.initialize_connection(vol, self.connr)
199
xml = libvirt_driver.connect_volume(connection_info, mount_device)
200
tree = ElementTree.fromstring(xml)
201
dev_str = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-0' % (location, iqn)
202
self.assertEqual(tree.get('type'), 'block')
203
self.assertEqual(tree.find('./source').get('dev'), dev_str)
204
libvirt_driver.disconnect_volume(connection_info, mount_device)
205
connection_info = vol_driver.terminate_connection(vol, self.connr)
206
expected_commands = [('iscsiadm', '-m', 'node', '-T', iqn,
208
('iscsiadm', '-m', 'node', '-T', iqn,
209
'-p', location, '--login'),
210
('iscsiadm', '-m', 'node', '-T', iqn,
211
'-p', location, '--op', 'update',
212
'-n', 'node.startup', '-v', 'automatic')]
213
self.assertEqual(self.executes, expected_commands)
215
def test_libvirt_sheepdog_driver(self):
216
vol_driver = volume_driver.SheepdogDriver()
217
libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
218
name = 'volume-00000001'
219
vol = {'id': 1, 'name': name}
220
connection_info = vol_driver.initialize_connection(vol, self.connr)
222
xml = libvirt_driver.connect_volume(connection_info, mount_device)
223
tree = ElementTree.fromstring(xml)
224
self.assertEqual(tree.get('type'), 'network')
225
self.assertEqual(tree.find('./source').get('protocol'), 'sheepdog')
226
self.assertEqual(tree.find('./source').get('name'), name)
227
libvirt_driver.disconnect_volume(connection_info, mount_device)
228
connection_info = vol_driver.terminate_connection(vol, self.connr)
230
def test_libvirt_rbd_driver(self):
231
vol_driver = volume_driver.RBDDriver()
232
libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
233
name = 'volume-00000001'
234
vol = {'id': 1, 'name': name}
235
connection_info = vol_driver.initialize_connection(vol, self.connr)
237
xml = libvirt_driver.connect_volume(connection_info, mount_device)
238
tree = ElementTree.fromstring(xml)
239
self.assertEqual(tree.get('type'), 'network')
240
self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
241
rbd_name = '%s/%s' % (FLAGS.rbd_pool, name)
242
self.assertEqual(tree.find('./source').get('name'), rbd_name)
243
self.assertEqual(tree.find('./source/auth'), None)
244
libvirt_driver.disconnect_volume(connection_info, mount_device)
245
connection_info = vol_driver.terminate_connection(vol, self.connr)
247
def test_libvirt_rbd_driver_auth_enabled(self):
248
vol_driver = volume_driver.RBDDriver()
249
libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
250
name = 'volume-00000001'
251
vol = {'id': 1, 'name': name}
252
connection_info = vol_driver.initialize_connection(vol, self.connr)
253
uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'
256
connection_info['data']['auth_enabled'] = True
257
connection_info['data']['auth_username'] = user
258
connection_info['data']['secret_type'] = secret_type
259
connection_info['data']['secret_uuid'] = uuid
261
xml = libvirt_driver.connect_volume(connection_info, mount_device)
262
tree = ElementTree.fromstring(xml)
263
self.assertEqual(tree.get('type'), 'network')
264
self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
265
rbd_name = '%s/%s' % (FLAGS.rbd_pool, name)
266
self.assertEqual(tree.find('./source').get('name'), rbd_name)
267
self.assertEqual(tree.find('./auth').get('username'), user)
268
self.assertEqual(tree.find('./auth/secret').get('type'), secret_type)
269
self.assertEqual(tree.find('./auth/secret').get('uuid'), uuid)
270
libvirt_driver.disconnect_volume(connection_info, mount_device)
271
connection_info = vol_driver.terminate_connection(vol, self.connr)
273
def test_libvirt_rbd_driver_auth_disabled(self):
274
vol_driver = volume_driver.RBDDriver()
275
libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
276
name = 'volume-00000001'
277
vol = {'id': 1, 'name': name}
278
connection_info = vol_driver.initialize_connection(vol, self.connr)
279
uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'
282
connection_info['data']['auth_enabled'] = False
283
connection_info['data']['auth_username'] = user
284
connection_info['data']['secret_type'] = secret_type
285
connection_info['data']['secret_uuid'] = uuid
287
xml = libvirt_driver.connect_volume(connection_info, mount_device)
288
tree = ElementTree.fromstring(xml)
289
self.assertEqual(tree.get('type'), 'network')
290
self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
291
rbd_name = '%s/%s' % (FLAGS.rbd_pool, name)
292
self.assertEqual(tree.find('./source').get('name'), rbd_name)
293
self.assertEqual(tree.find('./auth'), None)
294
libvirt_driver.disconnect_volume(connection_info, mount_device)
295
connection_info = vol_driver.terminate_connection(vol, self.connr)
297
def test_libvirt_lxc_volume(self):
298
self.stubs.Set(os.path, 'exists', lambda x: True)
299
vol_driver = volume_driver.ISCSIDriver()
300
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
301
location = '10.0.2.15:3260'
302
name = 'volume-00000001'
303
iqn = 'iqn.2010-10.org.openstack:%s' % name
306
'provider_auth': None,
307
'provider_location': '%s,fake %s' % (location, iqn)}
308
connection_info = vol_driver.initialize_connection(vol, self.connr)
310
xml = libvirt_driver.connect_volume(connection_info, mount_device)
311
tree = ElementTree.fromstring(xml)
312
dev_str = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-0' % (location, iqn)
313
self.assertEqual(tree.get('type'), 'block')
314
self.assertEqual(tree.find('./source').get('dev'), dev_str)
315
libvirt_driver.disconnect_volume(connection_info, mount_device)
316
connection_info = vol_driver.terminate_connection(vol, self.connr)
319
class CacheConcurrencyTestCase(test.TestCase):
321
super(CacheConcurrencyTestCase, self).setUp()
322
self.flags(instances_path='nova.compute.manager')
324
def fake_exists(fname):
325
basedir = os.path.join(FLAGS.instances_path, '_base')
330
def fake_execute(*args, **kwargs):
333
def fake_extend(image, size):
336
self.stubs.Set(os.path, 'exists', fake_exists)
337
self.stubs.Set(utils, 'execute', fake_execute)
338
self.stubs.Set(connection.disk, 'extend', fake_extend)
339
connection.libvirt_utils = fake_libvirt_utils
342
connection.libvirt_utils = libvirt_utils
343
super(CacheConcurrencyTestCase, self).tearDown()
345
def test_same_fname_concurrency(self):
346
"""Ensures that the same fname cache runs at a sequentially"""
347
conn = connection.LibvirtConnection
348
wait1 = eventlet.event.Event()
349
done1 = eventlet.event.Event()
350
eventlet.spawn(conn._cache_image, _concurrency,
351
'target', 'fname', False, None, wait1, done1)
352
wait2 = eventlet.event.Event()
353
done2 = eventlet.event.Event()
354
eventlet.spawn(conn._cache_image, _concurrency,
355
'target', 'fname', False, None, wait2, done2)
359
self.assertFalse(done2.ready())
364
self.assertTrue(done2.ready())
366
def test_different_fname_concurrency(self):
367
"""Ensures that two different fname caches are concurrent"""
368
conn = connection.LibvirtConnection
369
wait1 = eventlet.event.Event()
370
done1 = eventlet.event.Event()
371
eventlet.spawn(conn._cache_image, _concurrency,
372
'target', 'fname2', False, None, wait1, done1)
373
wait2 = eventlet.event.Event()
374
done2 = eventlet.event.Event()
375
eventlet.spawn(conn._cache_image, _concurrency,
376
'target', 'fname1', False, None, wait2, done2)
380
self.assertTrue(done2.ready())
386
class FakeVolumeDriver(object):
387
def __init__(self, *args, **kwargs):
390
def attach_volume(self, *args):
393
def detach_volume(self, *args):
396
def get_xml(self, *args):
400
def missing_libvirt():
401
return libvirt is None
404
class LibvirtConnTestCase(test.TestCase):
407
super(LibvirtConnTestCase, self).setUp()
408
connection._late_load_cheetah()
409
self.flags(fake_call=True)
410
self.user_id = 'fake'
411
self.project_id = 'fake'
412
self.context = context.get_admin_context()
413
self.flags(instances_path='')
414
self.call_libvirt_dependant_setup = False
415
connection.libvirt_utils = fake_libvirt_utils
417
def fake_extend(image, size):
420
self.stubs.Set(connection.disk, 'extend', fake_extend)
423
connection.libvirt_utils = libvirt_utils
424
super(LibvirtConnTestCase, self).tearDown()
426
test_instance = {'memory_kb': '1024000',
427
'basepath': '/some/path',
428
'bridge_name': 'br100',
430
'project_id': 'fake',
432
'image_ref': '155d900f-4e14-4e4c-a73d-069cbf4541e6',
435
'instance_type_id': '5'} # m1.small
437
def create_fake_libvirt_mock(self, **kwargs):
438
"""Defining mocks for LibvirtConnection(libvirt is not used)."""
440
# A fake libvirt.virConnect
441
class FakeLibvirtConnection(object):
442
def defineXML(self, xml):
443
return FakeVirtDomain()
446
volume_driver = 'iscsi=nova.tests.test_libvirt.FakeVolumeDriver'
447
self.flags(libvirt_volume_drivers=[volume_driver])
448
fake = FakeLibvirtConnection()
449
# Customizing above fake if necessary
450
for key, val in kwargs.items():
451
fake.__setattr__(key, val)
453
self.flags(image_service='nova.image.fake.FakeImageService')
454
self.flags(libvirt_vif_driver="nova.tests.fake_network.FakeVIFDriver")
456
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
457
connection.LibvirtConnection._conn = fake
459
def fake_lookup(self, instance_name):
460
return FakeVirtDomain()
462
def fake_execute(self, *args):
463
open(args[-1], "a").close()
465
def create_service(self, **kwargs):
466
service_ref = {'host': kwargs.get('host', 'dummy'),
467
'binary': 'nova-compute',
470
'availability_zone': 'zone'}
472
return db.service_create(context.get_admin_context(), service_ref)
474
def test_get_connector(self):
475
initiator = 'fake.initiator.iqn'
479
conn = connection.LibvirtConnection(True)
482
'initiator': initiator
487
result = conn.get_volume_connector(volume)
488
self.assertDictMatch(expected, result)
490
def test_preparing_xml_info(self):
491
conn = connection.LibvirtConnection(True)
492
instance_ref = db.instance_create(self.context, self.test_instance)
494
result = conn._prepare_xml_info(instance_ref,
495
_fake_network_info(self.stubs, 1),
497
self.assertTrue(len(result['nics']) == 1)
499
result = conn._prepare_xml_info(instance_ref,
500
_fake_network_info(self.stubs, 2),
502
self.assertTrue(len(result['nics']) == 2)
504
def test_xml_and_uri_no_ramdisk_no_kernel(self):
505
instance_data = dict(self.test_instance)
506
self._check_xml_and_uri(instance_data,
507
expect_kernel=False, expect_ramdisk=False)
509
def test_xml_and_uri_no_ramdisk(self):
510
instance_data = dict(self.test_instance)
511
instance_data['kernel_id'] = 'aki-deadbeef'
512
self._check_xml_and_uri(instance_data,
513
expect_kernel=True, expect_ramdisk=False)
515
def test_xml_and_uri_no_kernel(self):
516
instance_data = dict(self.test_instance)
517
instance_data['ramdisk_id'] = 'ari-deadbeef'
518
self._check_xml_and_uri(instance_data,
519
expect_kernel=False, expect_ramdisk=False)
521
def test_xml_and_uri(self):
522
instance_data = dict(self.test_instance)
523
instance_data['ramdisk_id'] = 'ari-deadbeef'
524
instance_data['kernel_id'] = 'aki-deadbeef'
525
self._check_xml_and_uri(instance_data,
526
expect_kernel=True, expect_ramdisk=True)
528
def test_xml_and_uri_rescue(self):
529
instance_data = dict(self.test_instance)
530
instance_data['ramdisk_id'] = 'ari-deadbeef'
531
instance_data['kernel_id'] = 'aki-deadbeef'
532
self._check_xml_and_uri(instance_data, expect_kernel=True,
533
expect_ramdisk=True, rescue=True)
535
def test_xml_uuid(self):
536
instance_data = dict(self.test_instance)
537
self._check_xml_and_uuid(instance_data)
539
def test_lxc_container_and_uri(self):
540
instance_data = dict(self.test_instance)
541
self._check_xml_and_container(instance_data)
543
def test_xml_disk_prefix(self):
544
instance_data = dict(self.test_instance)
545
self._check_xml_and_disk_prefix(instance_data)
547
def test_xml_disk_driver(self):
548
instance_data = dict(self.test_instance)
549
self._check_xml_and_disk_driver(instance_data)
551
def test_xml_disk_bus_virtio(self):
552
self._check_xml_and_disk_bus({"disk_format": "raw"},
555
def test_xml_disk_bus_ide(self):
556
self._check_xml_and_disk_bus({"disk_format": "iso"},
559
def test_list_instances(self):
560
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
561
connection.LibvirtConnection._conn.lookupByID = self.fake_lookup
562
connection.LibvirtConnection._conn.listDomainsID = lambda: [0, 1]
565
conn = connection.LibvirtConnection(False)
566
instances = conn.list_instances()
567
# Only one should be listed, since domain with ID 0 must be skiped
568
self.assertEquals(len(instances), 1)
570
def test_get_all_block_devices(self):
572
# NOTE(vish): id 0 is skipped
578
<source file='filename'/>
581
<source dev='/path/to/dev/1'/>
590
<source file='filename'/>
599
<source file='filename'/>
602
<source dev='/path/to/dev/3'/>
610
return FakeVirtDomain(xml[id])
612
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
613
connection.LibvirtConnection._conn.listDomainsID = lambda: range(4)
614
connection.LibvirtConnection._conn.lookupByID = fake_lookup
617
conn = connection.LibvirtConnection(False)
618
devices = conn.get_all_block_devices()
619
self.assertEqual(devices, ['/path/to/dev/1', '/path/to/dev/3'])
621
@test.skip_if(missing_libvirt(), "Test requires libvirt")
622
def test_snapshot_in_ami_format(self):
623
self.flags(image_service='nova.image.fake.FakeImageService')
626
image_service = utils.import_object(FLAGS.image_service)
628
# Assign different image_ref from nova/images/fakes for testing ami
629
test_instance = copy.deepcopy(self.test_instance)
630
test_instance["image_ref"] = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'
632
# Assuming that base image already exists in image_service
633
instance_ref = db.instance_create(self.context, test_instance)
634
properties = {'instance_id': instance_ref['id'],
635
'user_id': str(self.context.user_id)}
636
snapshot_name = 'test-snap'
637
sent_meta = {'name': snapshot_name, 'is_public': False,
638
'status': 'creating', 'properties': properties}
639
# Create new image. It will be updated in snapshot method
640
# To work with it from snapshot, the single image_service is needed
641
recv_meta = image_service.create(context, sent_meta)
643
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
644
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
645
self.mox.StubOutWithMock(connection.utils, 'execute')
646
connection.utils.execute = self.fake_execute
650
conn = connection.LibvirtConnection(False)
651
conn.snapshot(self.context, instance_ref, recv_meta['id'])
653
snapshot = image_service.show(context, recv_meta['id'])
654
self.assertEquals(snapshot['properties']['image_state'], 'available')
655
self.assertEquals(snapshot['status'], 'active')
656
self.assertEquals(snapshot['disk_format'], 'ami')
657
self.assertEquals(snapshot['name'], snapshot_name)
659
@test.skip_if(missing_libvirt(), "Test requires libvirt")
660
def test_snapshot_in_raw_format(self):
661
self.flags(image_service='nova.image.fake.FakeImageService')
664
image_service = utils.import_object(FLAGS.image_service)
666
# Assuming that base image already exists in image_service
667
instance_ref = db.instance_create(self.context, self.test_instance)
668
properties = {'instance_id': instance_ref['id'],
669
'user_id': str(self.context.user_id)}
670
snapshot_name = 'test-snap'
671
sent_meta = {'name': snapshot_name, 'is_public': False,
672
'status': 'creating', 'properties': properties}
673
# Create new image. It will be updated in snapshot method
674
# To work with it from snapshot, the single image_service is needed
675
recv_meta = image_service.create(context, sent_meta)
677
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
678
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
679
self.mox.StubOutWithMock(connection.utils, 'execute')
680
connection.utils.execute = self.fake_execute
684
conn = connection.LibvirtConnection(False)
685
conn.snapshot(self.context, instance_ref, recv_meta['id'])
687
snapshot = image_service.show(context, recv_meta['id'])
688
self.assertEquals(snapshot['properties']['image_state'], 'available')
689
self.assertEquals(snapshot['status'], 'active')
690
self.assertEquals(snapshot['disk_format'], 'raw')
691
self.assertEquals(snapshot['name'], snapshot_name)
693
@test.skip_if(missing_libvirt(), "Test requires libvirt")
694
def test_snapshot_in_qcow2_format(self):
695
self.flags(image_service='nova.image.fake.FakeImageService')
696
self.flags(snapshot_image_format='qcow2')
699
image_service = utils.import_object(FLAGS.image_service)
701
# Assuming that base image already exists in image_service
702
instance_ref = db.instance_create(self.context, self.test_instance)
703
properties = {'instance_id': instance_ref['id'],
704
'user_id': str(self.context.user_id)}
705
snapshot_name = 'test-snap'
706
sent_meta = {'name': snapshot_name, 'is_public': False,
707
'status': 'creating', 'properties': properties}
708
# Create new image. It will be updated in snapshot method
709
# To work with it from snapshot, the single image_service is needed
710
recv_meta = image_service.create(context, sent_meta)
712
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
713
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
714
self.mox.StubOutWithMock(connection.utils, 'execute')
715
connection.utils.execute = self.fake_execute
719
conn = connection.LibvirtConnection(False)
720
conn.snapshot(self.context, instance_ref, recv_meta['id'])
722
snapshot = image_service.show(context, recv_meta['id'])
723
self.assertEquals(snapshot['properties']['image_state'], 'available')
724
self.assertEquals(snapshot['status'], 'active')
725
self.assertEquals(snapshot['disk_format'], 'qcow2')
726
self.assertEquals(snapshot['name'], snapshot_name)
728
@test.skip_if(missing_libvirt(), "Test requires libvirt")
729
def test_snapshot_no_image_architecture(self):
730
self.flags(image_service='nova.image.fake.FakeImageService')
733
image_service = utils.import_object(FLAGS.image_service)
735
# Assign different image_ref from nova/images/fakes for
736
# testing different base image
737
test_instance = copy.deepcopy(self.test_instance)
738
test_instance["image_ref"] = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
740
# Assuming that base image already exists in image_service
741
instance_ref = db.instance_create(self.context, test_instance)
742
properties = {'instance_id': instance_ref['id'],
743
'user_id': str(self.context.user_id)}
744
snapshot_name = 'test-snap'
745
sent_meta = {'name': snapshot_name, 'is_public': False,
746
'status': 'creating', 'properties': properties}
747
# Create new image. It will be updated in snapshot method
748
# To work with it from snapshot, the single image_service is needed
749
recv_meta = image_service.create(context, sent_meta)
751
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
752
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
753
self.mox.StubOutWithMock(connection.utils, 'execute')
754
connection.utils.execute = self.fake_execute
758
conn = connection.LibvirtConnection(False)
759
conn.snapshot(self.context, instance_ref, recv_meta['id'])
761
snapshot = image_service.show(context, recv_meta['id'])
762
self.assertEquals(snapshot['properties']['image_state'], 'available')
763
self.assertEquals(snapshot['status'], 'active')
764
self.assertEquals(snapshot['name'], snapshot_name)
766
@test.skip_if(missing_libvirt(), "Test requires libvirt")
767
def test_snapshot_no_original_image(self):
768
self.flags(image_service='nova.image.fake.FakeImageService')
771
image_service = utils.import_object(FLAGS.image_service)
773
# Assign a non-existent image
774
test_instance = copy.deepcopy(self.test_instance)
775
test_instance["image_ref"] = '661122aa-1234-dede-fefe-babababababa'
777
instance_ref = db.instance_create(self.context, test_instance)
778
properties = {'instance_id': instance_ref['id'],
779
'user_id': str(self.context.user_id)}
780
snapshot_name = 'test-snap'
781
sent_meta = {'name': snapshot_name, 'is_public': False,
782
'status': 'creating', 'properties': properties}
783
recv_meta = image_service.create(context, sent_meta)
785
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
786
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
787
self.mox.StubOutWithMock(connection.utils, 'execute')
788
connection.utils.execute = self.fake_execute
792
conn = connection.LibvirtConnection(False)
793
conn.snapshot(self.context, instance_ref, recv_meta['id'])
795
snapshot = image_service.show(context, recv_meta['id'])
796
self.assertEquals(snapshot['properties']['image_state'], 'available')
797
self.assertEquals(snapshot['status'], 'active')
798
self.assertEquals(snapshot['name'], snapshot_name)
800
def test_attach_invalid_volume_type(self):
801
self.create_fake_libvirt_mock()
802
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
804
conn = connection.LibvirtConnection(False)
805
self.assertRaises(exception.VolumeDriverNotFound,
807
{"driver_volume_type": "badtype"},
811
def test_multi_nic(self):
812
instance_data = dict(self.test_instance)
813
network_info = _fake_network_info(self.stubs, 2)
814
conn = connection.LibvirtConnection(True)
815
instance_ref = db.instance_create(self.context, instance_data)
816
xml = conn.to_xml(instance_ref, network_info, None, False)
817
tree = ElementTree.fromstring(xml)
818
interfaces = tree.findall("./devices/interface")
819
self.assertEquals(len(interfaces), 2)
820
parameters = interfaces[0].findall('./filterref/parameter')
821
self.assertEquals(interfaces[0].get('type'), 'bridge')
822
self.assertEquals(parameters[0].get('name'), 'IP')
823
self.assertTrue(_ipv4_like(parameters[0].get('value'), '192.168'))
824
self.assertEquals(parameters[1].get('name'), 'DHCPSERVER')
825
self.assertTrue(_ipv4_like(parameters[1].get('value'), '192.168.*.1'))
827
def _check_xml_and_container(self, instance):
828
user_context = context.RequestContext(self.user_id,
830
instance_ref = db.instance_create(user_context, instance)
832
self.flags(libvirt_type='lxc')
833
conn = connection.LibvirtConnection(True)
835
self.assertEquals(conn.uri, 'lxc:///')
837
network_info = _fake_network_info(self.stubs, 1)
838
xml = conn.to_xml(instance_ref, network_info)
839
tree = ElementTree.fromstring(xml)
842
(lambda t: t.find('.').get('type'), 'lxc'),
843
(lambda t: t.find('./os/type').text, 'exe'),
844
(lambda t: t.find('./devices/filesystem/target').get('dir'), '/')]
846
for i, (check, expected_result) in enumerate(check):
847
self.assertEqual(check(tree),
849
'%s failed common check %d' % (xml, i))
851
target = tree.find('./devices/filesystem/source').get('dir')
852
self.assertTrue(len(target) > 0)
854
def _check_xml_and_disk_prefix(self, instance):
855
user_context = context.RequestContext(self.user_id,
857
instance_ref = db.instance_create(user_context, instance)
861
(lambda t: t.find('.').get('type'), 'qemu'),
862
(lambda t: t.find('./devices/disk/target').get('dev'), 'vda')],
864
(lambda t: t.find('.').get('type'), 'xen'),
865
(lambda t: t.find('./devices/disk/target').get('dev'), 'sda')],
867
(lambda t: t.find('.').get('type'), 'kvm'),
868
(lambda t: t.find('./devices/disk/target').get('dev'), 'vda')],
870
(lambda t: t.find('.').get('type'), 'uml'),
871
(lambda t: t.find('./devices/disk/target').get('dev'), 'ubda')]
874
for (libvirt_type, checks) in type_disk_map.iteritems():
875
self.flags(libvirt_type=libvirt_type)
876
conn = connection.LibvirtConnection(True)
878
network_info = _fake_network_info(self.stubs, 1)
879
xml = conn.to_xml(instance_ref, network_info)
880
tree = ElementTree.fromstring(xml)
882
for i, (check, expected_result) in enumerate(checks):
883
self.assertEqual(check(tree),
885
'%s != %s failed check %d' %
886
(check(tree), expected_result, i))
888
def _check_xml_and_disk_driver(self, image_meta):
890
directio_supported = True
892
def os_open_stub(path, flags, *args, **kwargs):
893
if flags & os.O_DIRECT:
894
if not directio_supported:
895
raise OSError(errno.EINVAL,
896
'%s: %s' % (os.strerror(errno.EINVAL), path))
897
flags &= ~os.O_DIRECT
898
return os_open(path, flags, *args, **kwargs)
900
self.stubs.Set(os, 'open', os_open_stub)
902
user_context = context.RequestContext(self.user_id, self.project_id)
903
instance_ref = db.instance_create(user_context, self.test_instance)
904
network_info = _fake_network_info(self.stubs, 1)
906
xml = connection.LibvirtConnection(True).to_xml(instance_ref,
909
tree = ElementTree.fromstring(xml)
910
disks = tree.findall('./devices/disk/driver')
912
self.assertEqual(disk.get("cache"), "none")
914
directio_supported = False
916
# The O_DIRECT availability is cached on first use in
917
# LibvirtConnection, hence we re-create it here
918
xml = connection.LibvirtConnection(True).to_xml(instance_ref,
921
tree = ElementTree.fromstring(xml)
922
disks = tree.findall('./devices/disk/driver')
924
self.assertEqual(disk.get("cache"), "writethrough")
926
def _check_xml_and_disk_bus(self, image_meta, device_type, bus):
927
user_context = context.RequestContext(self.user_id, self.project_id)
928
instance_ref = db.instance_create(user_context, self.test_instance)
929
network_info = _fake_network_info(self.stubs, 1)
931
xml = connection.LibvirtConnection(True).to_xml(instance_ref,
934
tree = ElementTree.fromstring(xml)
935
self.assertEqual(tree.find('./devices/disk').get('device'),
937
self.assertEqual(tree.find('./devices/disk/target').get('bus'), bus)
939
def _check_xml_and_uuid(self, image_meta):
940
user_context = context.RequestContext(self.user_id, self.project_id)
941
instance_ref = db.instance_create(user_context, self.test_instance)
942
network_info = _fake_network_info(self.stubs, 1)
944
xml = connection.LibvirtConnection(True).to_xml(instance_ref,
947
tree = ElementTree.fromstring(xml)
948
self.assertEqual(tree.find('./uuid').text,
949
instance_ref['uuid'])
951
def _check_xml_and_uri(self, instance, expect_ramdisk, expect_kernel,
953
user_context = context.RequestContext(self.user_id, self.project_id)
954
instance_ref = db.instance_create(user_context, instance)
955
network_ref = db.project_get_networks(context.get_admin_context(),
958
type_uri_map = {'qemu': ('qemu:///system',
959
[(lambda t: t.find('.').get('type'), 'qemu'),
960
(lambda t: t.find('./os/type').text, 'hvm'),
961
(lambda t: t.find('./devices/emulator'), None)]),
962
'kvm': ('qemu:///system',
963
[(lambda t: t.find('.').get('type'), 'kvm'),
964
(lambda t: t.find('./os/type').text, 'hvm'),
965
(lambda t: t.find('./devices/emulator'), None)]),
966
'uml': ('uml:///system',
967
[(lambda t: t.find('.').get('type'), 'uml'),
968
(lambda t: t.find('./os/type').text, 'uml')]),
970
[(lambda t: t.find('.').get('type'), 'xen'),
971
(lambda t: t.find('./os/type').text, 'linux')]),
974
for hypervisor_type in ['qemu', 'kvm', 'xen']:
975
check_list = type_uri_map[hypervisor_type][1]
978
check = (lambda t: t.find('./os/kernel').text.split('/')[1],
980
check_list.append(check)
981
check = (lambda t: t.find('./os/initrd').text.split('/')[1],
983
check_list.append(check)
986
check = (lambda t: t.find('./os/kernel').text.split(
989
check = (lambda t: t.find('./os/kernel'), None)
990
check_list.append(check)
993
check = (lambda t: t.find('./os/initrd').text.split(
996
check = (lambda t: t.find('./os/initrd'), None)
997
check_list.append(check)
999
if hypervisor_type in ['qemu', 'kvm']:
1000
check = (lambda t: t.findall('./devices/serial')[0].get(
1002
check_list.append(check)
1003
check = (lambda t: t.findall('./devices/serial')[1].get(
1005
check_list.append(check)
1006
check = (lambda t: t.findall('./devices/serial/source')[0].get(
1007
'path').split('/')[1], 'console.log')
1008
check_list.append(check)
1010
check = (lambda t: t.find('./devices/console').get(
1012
check_list.append(check)
1014
parameter = './devices/interface/filterref/parameter'
1016
(lambda t: t.find('.').tag, 'domain'),
1017
(lambda t: t.find(parameter).get('name'), 'IP'),
1018
(lambda t: _ipv4_like(t.find(parameter).get('value'), '192.168'),
1020
(lambda t: t.findall(parameter)[1].get('name'), 'DHCPSERVER'),
1021
(lambda t: _ipv4_like(t.findall(parameter)[1].get('value'),
1022
'192.168.*.1'), True),
1023
(lambda t: t.find('./memory').text, '2097152')]
1026
(lambda t: t.findall('./devices/disk/source')[0].get(
1027
'file').split('/')[1], 'disk.rescue'),
1028
(lambda t: t.findall('./devices/disk/source')[1].get(
1029
'file').split('/')[1], 'disk')]
1031
common_checks += [(lambda t: t.findall(
1032
'./devices/disk/source')[0].get('file').split('/')[1],
1034
common_checks += [(lambda t: t.findall(
1035
'./devices/disk/source')[1].get('file').split('/')[1],
1038
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
1039
self.flags(libvirt_type=libvirt_type)
1040
conn = connection.LibvirtConnection(True)
1042
self.assertEquals(conn.uri, expected_uri)
1044
network_info = _fake_network_info(self.stubs, 1)
1045
xml = conn.to_xml(instance_ref, network_info, None, rescue)
1046
tree = ElementTree.fromstring(xml)
1047
for i, (check, expected_result) in enumerate(checks):
1048
self.assertEqual(check(tree),
1050
'%s != %s failed check %d' %
1051
(check(tree), expected_result, i))
1053
for i, (check, expected_result) in enumerate(common_checks):
1054
self.assertEqual(check(tree),
1056
'%s != %s failed common check %d' %
1057
(check(tree), expected_result, i))
1059
# This test is supposed to make sure we don't
1060
# override a specifically set uri
1062
# Deliberately not just assigning this string to FLAGS.libvirt_uri and
1063
# checking against that later on. This way we make sure the
1064
# implementation doesn't fiddle around with the FLAGS.
1065
testuri = 'something completely different'
1066
self.flags(libvirt_uri=testuri)
1067
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
1068
self.flags(libvirt_type=libvirt_type)
1069
conn = connection.LibvirtConnection(True)
1070
self.assertEquals(conn.uri, testuri)
1071
db.instance_destroy(user_context, instance_ref['id'])
1073
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1074
def test_ensure_filtering_rules_for_instance_timeout(self):
1075
"""ensure_filtering_fules_for_instance() finishes with timeout."""
1077
def fake_none(self, *args):
1080
def fake_raise(self):
1081
raise libvirt.libvirtError('ERR')
1083
class FakeTime(object):
1090
fake_timer = FakeTime()
1092
# _fake_network_info must be called before create_fake_libvirt_mock(),
1093
# as _fake_network_info calls utils.import_class() and
1094
# create_fake_libvirt_mock() mocks utils.import_class().
1095
network_info = _fake_network_info(self.stubs, 1)
1096
self.create_fake_libvirt_mock()
1097
instance_ref = db.instance_create(self.context, self.test_instance)
1100
self.mox.ReplayAll()
1102
conn = connection.LibvirtConnection(False)
1103
self.stubs.Set(conn.firewall_driver,
1104
'setup_basic_filtering',
1106
self.stubs.Set(conn.firewall_driver,
1107
'prepare_instance_filter',
1109
self.stubs.Set(conn.firewall_driver,
1110
'instance_filter_exists',
1112
conn.ensure_filtering_rules_for_instance(instance_ref,
1115
except exception.Error, e:
1116
c1 = (0 <= e.message.find('Timeout migrating for'))
1119
self.assertEqual(29, fake_timer.counter, "Didn't wait the expected "
1122
db.instance_destroy(self.context, instance_ref['id'])
1124
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1125
def test_live_migration_raises_exception(self):
1126
"""Confirms recover method is called when exceptions are raised."""
1128
self.compute = utils.import_object(FLAGS.compute_manager)
1129
instance_dict = {'host': 'fake',
1130
'power_state': power_state.RUNNING,
1131
'vm_state': vm_states.ACTIVE}
1132
instance_ref = db.instance_create(self.context, self.test_instance)
1133
instance_ref = db.instance_update(self.context, instance_ref['id'],
1135
vol_dict = {'status': 'migrating', 'size': 1}
1136
volume_ref = db.volume_create(self.context, vol_dict)
1137
db.volume_attached(self.context, volume_ref['id'], instance_ref['id'],
1141
vdmock = self.mox.CreateMock(libvirt.virDomain)
1142
self.mox.StubOutWithMock(vdmock, "migrateToURI")
1143
_bandwidth = FLAGS.live_migration_bandwidth
1144
vdmock.migrateToURI(FLAGS.live_migration_uri % 'dest',
1147
_bandwidth).AndRaise(libvirt.libvirtError('ERR'))
1149
def fake_lookup(instance_name):
1150
if instance_name == instance_ref.name:
1153
self.create_fake_libvirt_mock(lookupByName=fake_lookup)
1154
self.mox.StubOutWithMock(self.compute, "rollback_live_migration")
1155
self.compute.rollback_live_migration(self.context, instance_ref,
1159
self.mox.ReplayAll()
1160
conn = connection.LibvirtConnection(False)
1161
self.assertRaises(libvirt.libvirtError,
1162
conn._live_migration,
1163
self.context, instance_ref, 'dest', False,
1164
self.compute.rollback_live_migration)
1166
instance_ref = db.instance_get(self.context, instance_ref['id'])
1167
self.assertTrue(instance_ref['vm_state'] == vm_states.ACTIVE)
1168
self.assertTrue(instance_ref['power_state'] == power_state.RUNNING)
1169
volume_ref = db.volume_get(self.context, volume_ref['id'])
1170
self.assertTrue(volume_ref['status'] == 'in-use')
1172
db.volume_destroy(self.context, volume_ref['id'])
1173
db.instance_destroy(self.context, instance_ref['id'])
1175
def test_pre_live_migration_works_correctly(self):
1176
"""Confirms pre_block_migration works correctly."""
1178
vol = {'block_device_mapping': [
1179
{'connection_info': 'dummy', 'mount_device': '/dev/sda'},
1180
{'connection_info': 'dummy', 'mount_device': '/dev/sdb'}]}
1181
conn = connection.LibvirtConnection(False)
1184
self.mox.StubOutWithMock(driver, "block_device_info_get_mapping")
1185
driver.block_device_info_get_mapping(vol
1186
).AndReturn(vol['block_device_mapping'])
1187
self.mox.StubOutWithMock(conn, "volume_driver_method")
1188
for v in vol['block_device_mapping']:
1189
conn.volume_driver_method('connect_volume',
1190
v['connection_info'], v['mount_device'])
1193
self.mox.ReplayAll()
1194
self.assertEqual(conn.pre_live_migration(vol), None)
1196
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1197
def test_pre_block_migration_works_correctly(self):
1198
"""Confirms pre_block_migration works correctly."""
1199
# Replace instances_path since this testcase creates tmpfile
1200
with utils.tempdir() as tmpdir:
1201
self.flags(instances_path=tmpdir)
1204
instance_ref = db.instance_create(self.context, self.test_instance)
1205
dummyjson = ('[{"path": "%s/disk", "disk_size": "10737418240",'
1206
' "type": "raw", "backing_file": ""}]')
1209
# qemu-img should be mockd since test environment might not have
1211
self.mox.ReplayAll()
1212
conn = connection.LibvirtConnection(False)
1213
conn.pre_block_migration(self.context, instance_ref,
1216
self.assertTrue(os.path.exists('%s/%s/' %
1217
(tmpdir, instance_ref.name)))
1219
db.instance_destroy(self.context, instance_ref['id'])
1221
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1222
def test_get_instance_disk_info_works_correctly(self):
1223
"""Confirms pre_block_migration works correctly."""
1225
instance_ref = db.instance_create(self.context, self.test_instance)
1226
dummyxml = ("<domain type='kvm'><name>instance-0000000a</name>"
1228
"<disk type='file'><driver name='qemu' type='raw'/>"
1229
"<source file='/test/disk'/>"
1230
"<target dev='vda' bus='virtio'/></disk>"
1231
"<disk type='file'><driver name='qemu' type='qcow2'/>"
1232
"<source file='/test/disk.local'/>"
1233
"<target dev='vdb' bus='virtio'/></disk>"
1234
"</devices></domain>")
1236
ret = ("image: /test/disk\n"
1237
"file format: raw\n"
1238
"virtual size: 20G (21474836480 bytes)\n"
1240
"cluster_size: 2097152\n"
1241
"backing file: /test/dummy (actual path: /backing/file)\n")
1244
vdmock = self.mox.CreateMock(libvirt.virDomain)
1245
self.mox.StubOutWithMock(vdmock, "XMLDesc")
1246
vdmock.XMLDesc(0).AndReturn(dummyxml)
1248
def fake_lookup(instance_name):
1249
if instance_name == instance_ref.name:
1251
self.create_fake_libvirt_mock(lookupByName=fake_lookup)
1253
GB = 1024 * 1024 * 1024
1254
fake_libvirt_utils.disk_sizes['/test/disk'] = 10 * GB
1255
fake_libvirt_utils.disk_sizes['/test/disk.local'] = 20 * GB
1256
fake_libvirt_utils.disk_backing_files['/test/disk.local'] = 'file'
1258
self.mox.StubOutWithMock(os.path, "getsize")
1259
os.path.getsize('/test/disk').AndReturn((10737418240))
1261
self.mox.StubOutWithMock(utils, "execute")
1262
utils.execute('qemu-img', 'info',
1263
'/test/disk.local').AndReturn((ret, ''))
1265
os.path.getsize('/test/disk.local').AndReturn((21474836480))
1267
self.mox.ReplayAll()
1268
conn = connection.LibvirtConnection(False)
1269
info = conn.get_instance_disk_info(instance_ref.name)
1270
info = utils.loads(info)
1271
self.assertEquals(info[0]['type'], 'raw')
1272
self.assertEquals(info[0]['path'], '/test/disk')
1273
self.assertEquals(info[0]['disk_size'], 10737418240)
1274
self.assertEquals(info[0]['backing_file'], "")
1275
self.assertEquals(info[1]['type'], 'qcow2')
1276
self.assertEquals(info[1]['path'], '/test/disk.local')
1277
self.assertEquals(info[1]['virt_disk_size'], 21474836480)
1278
self.assertEquals(info[1]['backing_file'], "file")
1280
db.instance_destroy(self.context, instance_ref['id'])
1282
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1283
def test_spawn_with_network_info(self):
1285
def fake_none(self, instance):
1288
# _fake_network_info must be called before create_fake_libvirt_mock(),
1289
# as _fake_network_info calls utils.import_class() and
1290
# create_fake_libvirt_mock() mocks utils.import_class().
1291
network_info = _fake_network_info(self.stubs, 1)
1292
self.create_fake_libvirt_mock()
1294
instance_ref = self.test_instance
1295
instance_ref['image_ref'] = 123456 # we send an int to test sha1 call
1296
instance = db.instance_create(self.context, instance_ref)
1299
self.mox.ReplayAll()
1300
conn = connection.LibvirtConnection(False)
1301
self.stubs.Set(conn.firewall_driver,
1302
'setup_basic_filtering',
1304
self.stubs.Set(conn.firewall_driver,
1305
'prepare_instance_filter',
1309
conn.spawn(self.context, instance, None, network_info)
1310
except Exception, e:
1311
# assert that no exception is raised due to sha1 receiving an int
1312
self.assertEqual(-1, str(e.message).find('must be string or buffer'
1314
count = (0 <= str(e.message).find('Unexpected method call'))
1316
path = os.path.join(FLAGS.instances_path, instance.name)
1317
if os.path.isdir(path):
1320
path = os.path.join(FLAGS.instances_path, '_base')
1321
if os.path.isdir(path):
1322
shutil.rmtree(os.path.join(FLAGS.instances_path, '_base'))
1324
def test_get_host_ip_addr(self):
1325
conn = connection.LibvirtConnection(False)
1326
ip = conn.get_host_ip_addr()
1327
self.assertEquals(ip, FLAGS.my_ip)
1329
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1330
def test_broken_connection(self):
1331
for (error, domain) in (
1332
(libvirt.VIR_ERR_SYSTEM_ERROR, libvirt.VIR_FROM_REMOTE),
1333
(libvirt.VIR_ERR_SYSTEM_ERROR, libvirt.VIR_FROM_RPC)):
1335
conn = connection.LibvirtConnection(False)
1337
self.mox.StubOutWithMock(conn, "_wrapped_conn")
1338
self.mox.StubOutWithMock(conn._wrapped_conn, "getCapabilities")
1339
self.mox.StubOutWithMock(libvirt.libvirtError, "get_error_code")
1340
self.mox.StubOutWithMock(libvirt.libvirtError, "get_error_domain")
1342
conn._wrapped_conn.getCapabilities().AndRaise(
1343
libvirt.libvirtError("fake failure"))
1345
libvirt.libvirtError.get_error_code().AndReturn(error)
1346
libvirt.libvirtError.get_error_domain().AndReturn(domain)
1348
self.mox.ReplayAll()
1350
self.assertFalse(conn._test_connection())
1352
self.mox.UnsetStubs()
1354
def test_volume_in_mapping(self):
1355
conn = connection.LibvirtConnection(False)
1356
swap = {'device_name': '/dev/sdb',
1358
ephemerals = [{'num': 0,
1359
'virtual_name': 'ephemeral0',
1360
'device_name': '/dev/sdc1',
1363
'virtual_name': 'ephemeral2',
1364
'device_name': '/dev/sdd',
1366
block_device_mapping = [{'mount_device': '/dev/sde',
1367
'device_path': 'fake_device'},
1368
{'mount_device': '/dev/sdf',
1369
'device_path': 'fake_device'}]
1370
block_device_info = {
1371
'root_device_name': '/dev/sda',
1373
'ephemerals': ephemerals,
1374
'block_device_mapping': block_device_mapping}
1376
def _assert_volume_in_mapping(device_name, true_or_false):
1377
self.assertEquals(conn._volume_in_mapping(device_name,
1381
_assert_volume_in_mapping('sda', False)
1382
_assert_volume_in_mapping('sdb', True)
1383
_assert_volume_in_mapping('sdc1', True)
1384
_assert_volume_in_mapping('sdd', True)
1385
_assert_volume_in_mapping('sde', True)
1386
_assert_volume_in_mapping('sdf', True)
1387
_assert_volume_in_mapping('sdg', False)
1388
_assert_volume_in_mapping('sdh1', False)
1390
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1391
def test_immediate_delete(self):
1392
conn = connection.LibvirtConnection(False)
1393
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
1394
connection.LibvirtConnection._conn.lookupByName = lambda x: None
1396
instance = db.instance_create(self.context, self.test_instance)
1397
conn.destroy(instance, {})
1399
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1400
def test_destroy_saved(self):
1401
"""Ensure destroy calls managedSaveRemove for saved instance"""
1402
mock = self.mox.CreateMock(libvirt.virDomain)
1404
mock.hasManagedSaveImage(0).AndReturn(1)
1405
mock.managedSaveRemove(0)
1408
self.mox.ReplayAll()
1410
def fake_lookup_by_name(instance_name):
1413
conn = connection.LibvirtConnection(False)
1414
self.stubs.Set(conn, '_lookup_by_name', fake_lookup_by_name)
1415
instance = {"name": "instancename", "id": "instanceid",
1416
"uuid": "875a8070-d0b9-4949-8b31-104d125c9a64"}
1417
conn.destroy(instance, [])
1419
def test_available_least_handles_missing(self):
1420
"""Ensure destroy calls managedSaveRemove for saved instance"""
1421
conn = connection.LibvirtConnection(False)
1423
def list_instances():
1425
self.stubs.Set(conn, 'list_instances', list_instances)
1427
def get_info(instance_name):
1428
raise exception.InstanceNotFound()
1429
self.stubs.Set(conn, 'get_instance_disk_info', get_info)
1431
result = conn.get_disk_available_least()
1432
space = fake_libvirt_utils.get_fs_info(FLAGS.instances_path)['free']
1433
self.assertEqual(result, space / 1024 ** 3)
1436
class HostStateTestCase(test.TestCase):
1438
cpu_info = ('{"vendor": "Intel", "model": "pentium", "arch": "i686", '
1439
'"features": ["ssse3", "monitor", "pni", "sse2", "sse", '
1440
'"fxsr", "clflush", "pse36", "pat", "cmov", "mca", "pge", '
1441
'"mtrr", "sep", "apic"], '
1442
'"topology": {"cores": "1", "threads": "1", "sockets": "1"}}')
1444
class FakeConnection(object):
1445
"""Fake connection object"""
1447
def get_vcpu_total(self):
1450
def get_vcpu_used(self):
1453
def get_cpu_info(self):
1454
return HostStateTestCase.cpu_info
1456
def get_local_gb_total(self):
1459
def get_local_gb_used(self):
1462
def get_memory_mb_total(self):
1465
def get_memory_mb_used(self):
1468
def get_hypervisor_type(self):
1471
def get_hypervisor_version(self):
1474
def get_disk_available_least(self):
1477
def test_update_status(self):
1478
self.mox.StubOutWithMock(connection, 'get_connection')
1479
connection.get_connection(True).AndReturn(self.FakeConnection())
1481
self.mox.ReplayAll()
1482
hs = connection.HostState(True)
1484
self.assertEquals(stats["vcpus"], 1)
1485
self.assertEquals(stats["vcpus_used"], 0)
1486
self.assertEquals(stats["cpu_info"],
1487
{"vendor": "Intel", "model": "pentium", "arch": "i686",
1488
"features": ["ssse3", "monitor", "pni", "sse2", "sse",
1489
"fxsr", "clflush", "pse36", "pat", "cmov",
1490
"mca", "pge", "mtrr", "sep", "apic"],
1491
"topology": {"cores": "1", "threads": "1", "sockets": "1"}
1493
self.assertEquals(stats["disk_total"], 100)
1494
self.assertEquals(stats["disk_used"], 20)
1495
self.assertEquals(stats["disk_available"], 80)
1496
self.assertEquals(stats["host_memory_total"], 497)
1497
self.assertEquals(stats["host_memory_free"], 409)
1498
self.assertEquals(stats["hypervisor_type"], 'QEMU')
1499
self.assertEquals(stats["hypervisor_version"], 13091)
1502
class NWFilterFakes:
1506
def nwfilterLookupByName(self, name):
1507
if name in self.filters:
1508
return self.filters[name]
1509
raise libvirt.libvirtError('Filter Not Found')
1511
def filterDefineXMLMock(self, xml):
1512
class FakeNWFilterInternal:
1513
def __init__(self, parent, name):
1515
self.parent = parent
1518
del self.parent.filters[self.name]
1520
tree = ElementTree.fromstring(xml)
1521
name = tree.get('name')
1522
if name not in self.filters:
1523
self.filters[name] = FakeNWFilterInternal(self, name)
1527
class IptablesFirewallTestCase(test.TestCase):
1529
super(IptablesFirewallTestCase, self).setUp()
1531
self.user_id = 'fake'
1532
self.project_id = 'fake'
1533
self.context = context.RequestContext(self.user_id, self.project_id)
1535
class FakeLibvirtConnection(object):
1536
def nwfilterDefineXML(*args, **kwargs):
1537
"""setup_basic_rules in nwfilter calls this."""
1539
self.fake_libvirt_connection = FakeLibvirtConnection()
1540
self.fw = firewall.IptablesFirewallDriver(
1541
get_connection=lambda: self.fake_libvirt_connection)
1544
'# Generated by iptables-save v1.4.10 on Sat Feb 19 00:03:19 2011',
1546
':PREROUTING ACCEPT [1170:189210]',
1547
':INPUT ACCEPT [844:71028]',
1548
':OUTPUT ACCEPT [5149:405186]',
1549
':POSTROUTING ACCEPT [5063:386098]',
1553
'# Generated by iptables-save v1.4.4 on Mon Dec 6 11:54:13 2010',
1555
':INPUT ACCEPT [969615:281627771]',
1556
':FORWARD ACCEPT [0:0]',
1557
':OUTPUT ACCEPT [915599:63811649]',
1558
':nova-block-ipv4 - [0:0]',
1559
'-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT ',
1560
'-A FORWARD -d 192.168.122.0/24 -o virbr0 -m state --state RELATED'
1561
',ESTABLISHED -j ACCEPT ',
1562
'-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT ',
1563
'-A FORWARD -i virbr0 -o virbr0 -j ACCEPT ',
1564
'-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable ',
1565
'-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable ',
1567
'# Completed on Mon Dec 6 11:54:13 2010',
1570
in6_filter_rules = [
1571
'# Generated by ip6tables-save v1.4.4 on Tue Jan 18 23:47:56 2011',
1573
':INPUT ACCEPT [349155:75810423]',
1574
':FORWARD ACCEPT [0:0]',
1575
':OUTPUT ACCEPT [349256:75777230]',
1577
'# Completed on Tue Jan 18 23:47:56 2011',
1580
def _create_instance_ref(self):
1581
return db.instance_create(self.context,
1583
'project_id': 'fake',
1584
'instance_type_id': 1})
1586
def test_static_filters(self):
1587
instance_ref = self._create_instance_ref()
1588
src_instance_ref = self._create_instance_ref()
1590
admin_ctxt = context.get_admin_context()
1591
secgroup = db.security_group_create(admin_ctxt,
1593
'project_id': 'fake',
1594
'name': 'testgroup',
1595
'description': 'test group'})
1597
src_secgroup = db.security_group_create(admin_ctxt,
1599
'project_id': 'fake',
1600
'name': 'testsourcegroup',
1601
'description': 'src group'})
1603
db.security_group_rule_create(admin_ctxt,
1604
{'parent_group_id': secgroup['id'],
1608
'cidr': '192.168.11.0/24'})
1610
db.security_group_rule_create(admin_ctxt,
1611
{'parent_group_id': secgroup['id'],
1615
'cidr': '192.168.11.0/24'})
1617
db.security_group_rule_create(admin_ctxt,
1618
{'parent_group_id': secgroup['id'],
1622
'cidr': '192.168.10.0/24'})
1624
db.security_group_rule_create(admin_ctxt,
1625
{'parent_group_id': secgroup['id'],
1629
'group_id': src_secgroup['id']})
1631
db.instance_add_security_group(admin_ctxt, instance_ref['uuid'],
1633
db.instance_add_security_group(admin_ctxt, src_instance_ref['uuid'],
1635
instance_ref = db.instance_get(admin_ctxt, instance_ref['id'])
1636
src_instance_ref = db.instance_get(admin_ctxt, src_instance_ref['id'])
1638
# self.fw.add_instance(instance_ref)
1639
def fake_iptables_execute(*cmd, **kwargs):
1640
process_input = kwargs.get('process_input', None)
1641
if cmd == ('ip6tables-save', '-t', 'filter'):
1642
return '\n'.join(self.in6_filter_rules), None
1643
if cmd == ('iptables-save', '-t', 'filter'):
1644
return '\n'.join(self.in_filter_rules), None
1645
if cmd == ('iptables-save', '-t', 'nat'):
1646
return '\n'.join(self.in_nat_rules), None
1647
if cmd == ('iptables-restore',):
1648
lines = process_input.split('\n')
1649
if '*filter' in lines:
1650
self.out_rules = lines
1652
if cmd == ('ip6tables-restore',):
1653
lines = process_input.split('\n')
1654
if '*filter' in lines:
1655
self.out6_rules = lines
1659
network_model = _fake_network_info(self.stubs, 1, spectacular=True)
1661
from nova.network import linux_net
1662
linux_net.iptables_manager.execute = fake_iptables_execute
1664
_fake_stub_out_get_nw_info(self.stubs, lambda *a, **kw: network_model)
1666
network_info = compute_utils.legacy_network_info(network_model)
1667
self.fw.prepare_instance_filter(instance_ref, network_info)
1668
self.fw.apply_instance_filter(instance_ref, network_info)
1670
in_rules = filter(lambda l: not l.startswith('#'),
1671
self.in_filter_rules)
1672
for rule in in_rules:
1673
if not 'nova' in rule:
1674
self.assertTrue(rule in self.out_rules,
1675
'Rule went missing: %s' % rule)
1677
instance_chain = None
1678
for rule in self.out_rules:
1679
# This is pretty crude, but it'll do for now
1680
# last two octets change
1681
if re.search('-d 192.168.[0-9]{1,3}.[0-9]{1,3} -j', rule):
1682
instance_chain = rule.split(' ')[-1]
1684
self.assertTrue(instance_chain, "The instance chain wasn't added")
1686
security_group_chain = None
1687
for rule in self.out_rules:
1688
# This is pretty crude, but it'll do for now
1689
if '-A %s -j' % instance_chain in rule:
1690
security_group_chain = rule.split(' ')[-1]
1692
self.assertTrue(security_group_chain,
1693
"The security group chain wasn't added")
1695
regex = re.compile('-A .* -j ACCEPT -p icmp -s 192.168.11.0/24')
1696
self.assertTrue(len(filter(regex.match, self.out_rules)) > 0,
1697
"ICMP acceptance rule wasn't added")
1699
regex = re.compile('-A .* -j ACCEPT -p icmp -m icmp --icmp-type 8'
1700
' -s 192.168.11.0/24')
1701
self.assertTrue(len(filter(regex.match, self.out_rules)) > 0,
1702
"ICMP Echo Request acceptance rule wasn't added")
1704
for ip in network_model.fixed_ips():
1705
if ip['version'] != 4:
1707
regex = re.compile('-A .* -j ACCEPT -p tcp -m multiport '
1708
'--dports 80:81 -s %s' % ip['address'])
1709
self.assertTrue(len(filter(regex.match, self.out_rules)) > 0,
1710
"TCP port 80/81 acceptance rule wasn't added")
1712
regex = re.compile('-A .* -j ACCEPT -p tcp '
1713
'-m multiport --dports 80:81 -s 192.168.10.0/24')
1714
self.assertTrue(len(filter(regex.match, self.out_rules)) > 0,
1715
"TCP port 80/81 acceptance rule wasn't added")
1716
db.instance_destroy(admin_ctxt, instance_ref['id'])
1718
def test_filters_for_instance_with_ip_v6(self):
1719
self.flags(use_ipv6=True)
1720
network_info = _fake_network_info(self.stubs, 1)
1721
rulesv4, rulesv6 = self.fw._filters_for_instance("fake", network_info)
1722
self.assertEquals(len(rulesv4), 2)
1723
self.assertEquals(len(rulesv6), 1)
1725
def test_filters_for_instance_without_ip_v6(self):
1726
self.flags(use_ipv6=False)
1727
network_info = _fake_network_info(self.stubs, 1)
1728
rulesv4, rulesv6 = self.fw._filters_for_instance("fake", network_info)
1729
self.assertEquals(len(rulesv4), 2)
1730
self.assertEquals(len(rulesv6), 0)
1732
def test_multinic_iptables(self):
1733
ipv4_rules_per_addr = 1
1734
ipv4_addr_per_network = 2
1735
ipv6_rules_per_addr = 1
1736
ipv6_addr_per_network = 1
1738
instance_ref = self._create_instance_ref()
1739
network_info = _fake_network_info(self.stubs, networks_count,
1740
ipv4_addr_per_network)
1741
ipv4_len = len(self.fw.iptables.ipv4['filter'].rules)
1742
ipv6_len = len(self.fw.iptables.ipv6['filter'].rules)
1743
inst_ipv4, inst_ipv6 = self.fw.instance_rules(instance_ref,
1745
self.fw.prepare_instance_filter(instance_ref, network_info)
1746
ipv4 = self.fw.iptables.ipv4['filter'].rules
1747
ipv6 = self.fw.iptables.ipv6['filter'].rules
1748
ipv4_network_rules = len(ipv4) - len(inst_ipv4) - ipv4_len
1749
ipv6_network_rules = len(ipv6) - len(inst_ipv6) - ipv6_len
1750
self.assertEquals(ipv4_network_rules,
1751
ipv4_rules_per_addr * ipv4_addr_per_network * networks_count)
1752
self.assertEquals(ipv6_network_rules,
1753
ipv6_rules_per_addr * ipv6_addr_per_network * networks_count)
1755
def test_do_refresh_security_group_rules(self):
1756
instance_ref = self._create_instance_ref()
1757
self.mox.StubOutWithMock(self.fw,
1758
'add_filters_for_instance',
1759
use_mock_anything=True)
1760
self.fw.prepare_instance_filter(instance_ref, mox.IgnoreArg())
1761
self.fw.instances[instance_ref['id']] = instance_ref
1762
self.mox.ReplayAll()
1763
self.fw.do_refresh_security_group_rules("fake")
1765
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1766
def test_unfilter_instance_undefines_nwfilter(self):
1767
admin_ctxt = context.get_admin_context()
1769
fakefilter = NWFilterFakes()
1770
_xml_mock = fakefilter.filterDefineXMLMock
1771
self.fw.nwfilter._conn.nwfilterDefineXML = _xml_mock
1772
_lookup_name = fakefilter.nwfilterLookupByName
1773
self.fw.nwfilter._conn.nwfilterLookupByName = _lookup_name
1774
instance_ref = self._create_instance_ref()
1776
network_info = _fake_network_info(self.stubs, 1)
1777
self.fw.setup_basic_filtering(instance_ref, network_info)
1778
self.fw.prepare_instance_filter(instance_ref, network_info)
1779
self.fw.apply_instance_filter(instance_ref, network_info)
1780
original_filter_count = len(fakefilter.filters)
1781
self.fw.unfilter_instance(instance_ref, network_info)
1783
# should undefine just the instance filter
1784
self.assertEqual(original_filter_count - len(fakefilter.filters), 1)
1786
db.instance_destroy(admin_ctxt, instance_ref['id'])
1788
def test_provider_firewall_rules(self):
1789
# setup basic instance data
1790
instance_ref = self._create_instance_ref()
1791
# FRAGILE: peeks at how the firewall names chains
1792
chain_name = 'inst-%s' % instance_ref['id']
1794
# create a firewall via setup_basic_filtering like libvirt_conn.spawn
1795
# should have a chain with 0 rules
1796
network_info = _fake_network_info(self.stubs, 1)
1797
self.fw.setup_basic_filtering(instance_ref, network_info)
1798
self.assertTrue('provider' in self.fw.iptables.ipv4['filter'].chains)
1799
rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
1800
if rule.chain == 'provider']
1801
self.assertEqual(0, len(rules))
1803
admin_ctxt = context.get_admin_context()
1804
# add a rule and send the update message, check for 1 rule
1805
provider_fw0 = db.provider_fw_rule_create(admin_ctxt,
1807
'cidr': '10.99.99.99/32',
1810
self.fw.refresh_provider_fw_rules()
1811
rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
1812
if rule.chain == 'provider']
1813
self.assertEqual(1, len(rules))
1815
# Add another, refresh, and make sure number of rules goes to two
1816
provider_fw1 = db.provider_fw_rule_create(admin_ctxt,
1818
'cidr': '10.99.99.99/32',
1821
self.fw.refresh_provider_fw_rules()
1822
rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
1823
if rule.chain == 'provider']
1824
self.assertEqual(2, len(rules))
1826
# create the instance filter and make sure it has a jump rule
1827
self.fw.prepare_instance_filter(instance_ref, network_info)
1828
self.fw.apply_instance_filter(instance_ref, network_info)
1829
inst_rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
1830
if rule.chain == chain_name]
1831
jump_rules = [rule for rule in inst_rules if '-j' in rule.rule]
1833
# IptablesTable doesn't make rules unique internally
1834
for rule in jump_rules:
1835
if 'provider' in rule.rule and rule not in provjump_rules:
1836
provjump_rules.append(rule)
1837
self.assertEqual(1, len(provjump_rules))
1839
# remove a rule from the db, cast to compute to refresh rule
1840
db.provider_fw_rule_destroy(admin_ctxt, provider_fw1['id'])
1841
self.fw.refresh_provider_fw_rules()
1842
rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
1843
if rule.chain == 'provider']
1844
self.assertEqual(1, len(rules))
1847
class NWFilterTestCase(test.TestCase):
1849
super(NWFilterTestCase, self).setUp()
1854
self.user_id = 'fake'
1855
self.project_id = 'fake'
1856
self.context = context.RequestContext(self.user_id, self.project_id)
1858
self.fake_libvirt_connection = Mock()
1860
self.fw = firewall.NWFilterFirewall(
1861
lambda: self.fake_libvirt_connection)
1863
def test_cidr_rule_nwfilter_xml(self):
1864
cloud_controller = cloud.CloudController()
1865
cloud_controller.create_security_group(self.context,
1867
'test group description')
1868
cloud_controller.authorize_security_group_ingress(self.context,
1873
cidr_ip='0.0.0.0/0')
1875
security_group = db.security_group_get_by_name(self.context,
1878
self.teardown_security_group()
1880
def teardown_security_group(self):
1881
cloud_controller = cloud.CloudController()
1882
cloud_controller.delete_security_group(self.context, 'testgroup')
1884
def setup_and_return_security_group(self):
1885
cloud_controller = cloud.CloudController()
1886
cloud_controller.create_security_group(self.context,
1888
'test group description')
1889
cloud_controller.authorize_security_group_ingress(self.context,
1894
cidr_ip='0.0.0.0/0')
1896
return db.security_group_get_by_name(self.context, 'fake', 'testgroup')
1898
def _create_instance(self):
1899
return db.instance_create(self.context,
1901
'project_id': 'fake',
1902
'instance_type_id': 1})
1904
def _create_instance_type(self, params=None):
1905
"""Create a test instance"""
1909
context = self.context.elevated()
1911
inst['name'] = 'm1.small'
1912
inst['memory_mb'] = '1024'
1914
inst['root_gb'] = '10'
1915
inst['ephemeral_gb'] = '20'
1916
inst['flavorid'] = '1'
1917
inst['swap'] = '2048'
1918
inst['rxtx_factor'] = 1
1920
return db.instance_type_create(context, inst)['id']
1922
def test_creates_base_rule_first(self):
1923
# These come pre-defined by libvirt
1924
self.defined_filters = ['no-mac-spoofing',
1927
'allow-dhcp-server']
1929
self.recursive_depends = {}
1930
for f in self.defined_filters:
1931
self.recursive_depends[f] = []
1933
def _filterDefineXMLMock(xml):
1934
dom = minidom.parseString(xml)
1935
name = dom.firstChild.getAttribute('name')
1936
self.recursive_depends[name] = []
1937
for f in dom.getElementsByTagName('filterref'):
1938
ref = f.getAttribute('filter')
1939
self.assertTrue(ref in self.defined_filters,
1940
('%s referenced filter that does ' +
1941
'not yet exist: %s') % (name, ref))
1942
dependencies = [ref] + self.recursive_depends[ref]
1943
self.recursive_depends[name] += dependencies
1945
self.defined_filters.append(name)
1948
self.fake_libvirt_connection.nwfilterDefineXML = _filterDefineXMLMock
1950
instance_ref = self._create_instance()
1951
inst_id = instance_ref['id']
1952
inst_uuid = instance_ref['uuid']
1954
def _ensure_all_called(mac):
1955
instance_filter = 'nova-instance-%s-%s' % (instance_ref['name'],
1956
mac.translate(None, ':'))
1957
for required in ['allow-dhcp-server',
1958
'no-arp-spoofing', 'no-ip-spoofing',
1960
self.assertTrue(required in
1961
self.recursive_depends[instance_filter],
1962
"Instance's filter does not include %s" %
1965
self.security_group = self.setup_and_return_security_group()
1967
db.instance_add_security_group(self.context, inst_uuid,
1968
self.security_group.id)
1969
instance = db.instance_get(self.context, inst_id)
1971
network_info = _fake_network_info(self.stubs, 1)
1972
# since there is one (network_info) there is one vif
1973
# pass this vif's mac to _ensure_all_called()
1974
# to set the instance_filter properly
1975
mac = network_info[0][1]['mac']
1977
self.fw.setup_basic_filtering(instance, network_info)
1978
_ensure_all_called(mac)
1979
db.instance_remove_security_group(self.context, inst_uuid,
1980
self.security_group.id)
1981
self.teardown_security_group()
1982
db.instance_destroy(context.get_admin_context(), instance_ref['id'])
1984
def test_unfilter_instance_undefines_nwfilters(self):
1985
admin_ctxt = context.get_admin_context()
1987
fakefilter = NWFilterFakes()
1988
self.fw._conn.nwfilterDefineXML = fakefilter.filterDefineXMLMock
1989
self.fw._conn.nwfilterLookupByName = fakefilter.nwfilterLookupByName
1991
instance_ref = self._create_instance()
1992
inst_id = instance_ref['id']
1993
inst_uuid = instance_ref['uuid']
1995
self.security_group = self.setup_and_return_security_group()
1997
db.instance_add_security_group(self.context, inst_uuid,
1998
self.security_group.id)
2000
instance = db.instance_get(self.context, inst_id)
2002
network_info = _fake_network_info(self.stubs, 1)
2003
self.fw.setup_basic_filtering(instance, network_info)
2004
original_filter_count = len(fakefilter.filters)
2005
self.fw.unfilter_instance(instance, network_info)
2006
self.assertEqual(original_filter_count - len(fakefilter.filters), 1)
2008
db.instance_destroy(admin_ctxt, instance_ref['id'])
2011
class LibvirtUtilsTestCase(test.TestCase):
2012
def test_get_iscsi_initiator(self):
2013
self.mox.StubOutWithMock(utils, 'execute')
2014
initiator = 'fake.initiator.iqn'
2015
rval = ("junk\nInitiatorName=%s\njunk\n" % initiator, None)
2016
utils.execute('cat', '/etc/iscsi/initiatorname.iscsi',
2017
run_as_root=True).AndReturn(rval)
2019
self.mox.ReplayAll()
2020
result = libvirt_utils.get_iscsi_initiator()
2021
self.assertEqual(initiator, result)
2023
def test_create_image(self):
2024
self.mox.StubOutWithMock(utils, 'execute')
2025
utils.execute('qemu-img', 'create', '-f', 'raw',
2026
'/some/path', '10G')
2027
utils.execute('qemu-img', 'create', '-f', 'qcow2',
2028
'/some/stuff', '1234567891234')
2030
self.mox.ReplayAll()
2031
libvirt_utils.create_image('raw', '/some/path', '10G')
2032
libvirt_utils.create_image('qcow2', '/some/stuff', '1234567891234')
2034
def test_create_cow_image(self):
2035
self.mox.StubOutWithMock(utils, 'execute')
2036
utils.execute('qemu-img', 'create', '-f', 'qcow2',
2037
'-o', 'cluster_size=2M,backing_file=/some/path',
2040
self.mox.ReplayAll()
2041
libvirt_utils.create_cow_image('/some/path', '/the/new/cow')
2043
def test_get_disk_size(self):
2044
self.mox.StubOutWithMock(utils, 'execute')
2045
utils.execute('qemu-img',
2047
'/some/path').AndReturn(('''image: 00000001
2049
virtual size: 4.4M (4592640 bytes)
2050
disk size: 4.4M''', ''))
2053
self.mox.ReplayAll()
2054
self.assertEquals(libvirt_utils.get_disk_size('/some/path'), 4592640)
2056
def test_copy_image(self):
2057
dst_fd, dst_path = tempfile.mkstemp()
2061
src_fd, src_path = tempfile.mkstemp()
2063
with os.fdopen(src_fd, 'w') as fp:
2066
libvirt_utils.copy_image(src_path, dst_path)
2067
with open(dst_path, 'r') as fp:
2068
self.assertEquals(fp.read(), 'canary')
2074
def test_mkfs(self):
2075
self.mox.StubOutWithMock(utils, 'execute')
2076
utils.execute('mkfs', '-t', 'ext4', '/my/block/dev')
2077
utils.execute('mkswap', '/my/swap/block/dev')
2078
self.mox.ReplayAll()
2080
libvirt_utils.mkfs('ext4', '/my/block/dev')
2081
libvirt_utils.mkfs('swap', '/my/swap/block/dev')
2083
def test_ensure_tree(self):
2084
with utils.tempdir() as tmpdir:
2085
testdir = '%s/foo/bar/baz' % (tmpdir,)
2086
libvirt_utils.ensure_tree(testdir)
2087
self.assertTrue(os.path.isdir(testdir))
2089
def test_write_to_file(self):
2090
dst_fd, dst_path = tempfile.mkstemp()
2094
libvirt_utils.write_to_file(dst_path, 'hello')
2095
with open(dst_path, 'r') as fp:
2096
self.assertEquals(fp.read(), 'hello')
2100
def test_write_to_file_with_umask(self):
2101
dst_fd, dst_path = tempfile.mkstemp()
2106
libvirt_utils.write_to_file(dst_path, 'hello', umask=0277)
2107
with open(dst_path, 'r') as fp:
2108
self.assertEquals(fp.read(), 'hello')
2109
mode = os.stat(dst_path).st_mode
2110
self.assertEquals(mode & 0277, 0)
2114
def test_chown(self):
2115
self.mox.StubOutWithMock(utils, 'execute')
2116
utils.execute('chown', 'soren', '/some/path', run_as_root=True)
2117
self.mox.ReplayAll()
2118
libvirt_utils.chown('/some/path', 'soren')
2120
def test_extract_snapshot(self):
2121
self.mox.StubOutWithMock(utils, 'execute')
2122
utils.execute('qemu-img', 'convert', '-f', 'qcow2', '-O', 'raw',
2123
'-s', 'snap1', '/path/to/disk/image', '/extracted/snap')
2126
self.mox.ReplayAll()
2127
libvirt_utils.extract_snapshot('/path/to/disk/image', 'qcow2',
2128
'snap1', '/extracted/snap', 'raw')
2130
def test_load_file(self):
2131
dst_fd, dst_path = tempfile.mkstemp()
2135
# We have a test for write_to_file. If that is sound, this suffices
2136
libvirt_utils.write_to_file(dst_path, 'hello')
2137
self.assertEquals(libvirt_utils.load_file(dst_path), 'hello')
2141
def test_file_open(self):
2142
dst_fd, dst_path = tempfile.mkstemp()
2146
# We have a test for write_to_file. If that is sound, this suffices
2147
libvirt_utils.write_to_file(dst_path, 'hello')
2148
with libvirt_utils.file_open(dst_path, 'r') as fp:
2149
self.assertEquals(fp.read(), 'hello')
2153
def test_get_fs_info(self):
2155
class FakeStatResult(object):
2159
self.f_frsize = 4096
2160
self.f_blocks = 2000
2167
self.f_namemax = 255
2171
def fake_statvfs(path):
2173
return FakeStatResult()
2175
self.stubs.Set(os, 'statvfs', fake_statvfs)
2177
fs_info = libvirt_utils.get_fs_info('/some/file/path')
2178
self.assertEquals('/some/file/path', self.path)
2179
self.assertEquals(8192000, fs_info['total'])
2180
self.assertEquals(3686400, fs_info['free'])
2181
self.assertEquals(4096000, fs_info['used'])
2183
def test_fetch_image(self):
2184
self.mox.StubOutWithMock(images, 'fetch_to_raw')
2186
context = 'opaque context'
2187
target = '/tmp/targetfile'
2191
images.fetch_to_raw(context, image_id, target, user_id, project_id)
2193
self.mox.ReplayAll()
2194
libvirt_utils.fetch_image(context, target, image_id,
2195
user_id, project_id)
2198
class LibvirtConnectionTestCase(test.TestCase):
2199
"""Test for nova.virt.libvirt.connection.LibvirtConnection."""
2201
super(LibvirtConnectionTestCase, self).setUp()
2202
self.libvirtconnection = connection.LibvirtConnection(read_only=True)
2204
def _create_instance(self, params=None):
2205
"""Create a test instance"""
2210
inst['image_ref'] = '1'
2211
inst['reservation_id'] = 'r-fakeres'
2212
inst['launch_time'] = '10'
2213
inst['user_id'] = 'fake'
2214
inst['project_id'] = 'fake'
2215
type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
2216
inst['instance_type_id'] = type_id
2217
inst['ami_launch_index'] = 0
2218
inst['host'] = 'host1'
2219
inst['root_gb'] = 10
2220
inst['ephemeral_gb'] = 20
2221
inst['config_drive'] = 1
2222
inst['kernel_id'] = 2
2223
inst['ramdisk_id'] = 3
2224
inst['config_drive_id'] = 1
2225
inst['key_data'] = 'ABCDEFG'
2228
return db.instance_create(context.get_admin_context(), inst)
2230
def test_migrate_disk_and_power_off_exception(self):
2231
"""Test for nova.virt.libvirt.connection.LivirtConnection
2232
.migrate_disk_and_power_off. """
2236
def fake_get_instance_disk_info(instance):
2239
def fake_destroy(instance, network_info, cleanup=True):
2242
def fake_get_host_ip_addr():
2245
def fake_execute(*args, **kwargs):
2247
if self.counter == 1:
2248
assert False, "intentional failure"
2250
def fake_os_path_exists(path):
2253
self.stubs.Set(self.libvirtconnection, 'get_instance_disk_info',
2254
fake_get_instance_disk_info)
2255
self.stubs.Set(self.libvirtconnection, '_destroy', fake_destroy)
2256
self.stubs.Set(self.libvirtconnection, 'get_host_ip_addr',
2257
fake_get_host_ip_addr)
2258
self.stubs.Set(utils, 'execute', fake_execute)
2259
self.stubs.Set(os.path, 'exists', fake_os_path_exists)
2261
ins_ref = self._create_instance()
2263
self.assertRaises(AssertionError,
2264
self.libvirtconnection.migrate_disk_and_power_off,
2265
None, ins_ref, '10.0.0.2', None, None)
2267
def test_migrate_disk_and_power_off(self):
2268
"""Test for nova.virt.libvirt.connection.LivirtConnection
2269
.migrate_disk_and_power_off. """
2271
disk_info = [{'type': 'qcow2', 'path': '/test/disk',
2272
'virt_disk_size': '10737418240',
2273
'backing_file': '/base/disk',
2274
'disk_size':'83886080'},
2275
{'type': 'raw', 'path': '/test/disk.local',
2276
'virt_disk_size': '10737418240',
2277
'backing_file': '/base/disk.local',
2278
'disk_size':'83886080'}]
2279
disk_info_text = utils.dumps(disk_info)
2281
def fake_get_instance_disk_info(instance):
2282
return disk_info_text
2284
def fake_destroy(instance, network_info, cleanup=True):
2287
def fake_get_host_ip_addr():
2290
def fake_execute(*args, **kwargs):
2293
self.stubs.Set(self.libvirtconnection, 'get_instance_disk_info',
2294
fake_get_instance_disk_info)
2295
self.stubs.Set(self.libvirtconnection, '_destroy', fake_destroy)
2296
self.stubs.Set(self.libvirtconnection, 'get_host_ip_addr',
2297
fake_get_host_ip_addr)
2298
self.stubs.Set(utils, 'execute', fake_execute)
2300
ins_ref = self._create_instance()
2301
""" dest is different host case """
2302
out = self.libvirtconnection.migrate_disk_and_power_off(
2303
None, ins_ref, '10.0.0.2', None, None)
2304
self.assertEquals(out, disk_info_text)
2306
""" dest is same host case """
2307
out = self.libvirtconnection.migrate_disk_and_power_off(
2308
None, ins_ref, '10.0.0.1', None, None)
2309
self.assertEquals(out, disk_info_text)
2311
def test_wait_for_running(self):
2312
"""Test for nova.virt.libvirt.connection.LivirtConnection
2313
._wait_for_running. """
2315
def fake_get_info(instance):
2316
if instance['name'] == "not_found":
2317
raise exception.NotFound
2318
elif instance['name'] == "running":
2319
return {'state': power_state.RUNNING}
2321
return {'state': power_state.SHUTOFF}
2323
self.stubs.Set(self.libvirtconnection, 'get_info',
2326
""" instance not found case """
2327
self.assertRaises(utils.LoopingCallDone,
2328
self.libvirtconnection._wait_for_running,
2329
{'name': 'not_found',
2330
'uuid': 'not_found_uuid'})
2332
""" instance is running case """
2333
self.assertRaises(utils.LoopingCallDone,
2334
self.libvirtconnection._wait_for_running,
2336
'uuid': 'running_uuid'})
2339
self.libvirtconnection._wait_for_running({'name': 'else',
2340
'uuid': 'other_uuid'})
2342
def test_finish_migration(self):
2343
"""Test for nova.virt.libvirt.connection.LivirtConnection
2344
.finish_migration. """
2346
disk_info = [{'type': 'qcow2', 'path': '/test/disk',
2347
'local_gb': 10, 'backing_file': '/base/disk'},
2348
{'type': 'raw', 'path': '/test/disk.local',
2349
'local_gb': 10, 'backing_file': '/base/disk.local'}]
2350
disk_info_text = utils.dumps(disk_info)
2352
def fake_extend(path, size):
2355
def fake_to_xml(instance, network_info):
2358
def fake_plug_vifs(instance, network_info):
2361
def fake_create_image(context, inst, libvirt_xml, suffix='',
2362
disk_images=None, network_info=None,
2363
block_device_info=None):
2366
def fake_create_new_domain(xml):
2369
def fake_execute(*args, **kwargs):
2372
self.flags(use_cow_images=True)
2373
self.stubs.Set(connection.disk, 'extend', fake_extend)
2374
self.stubs.Set(self.libvirtconnection, 'to_xml', fake_to_xml)
2375
self.stubs.Set(self.libvirtconnection, 'plug_vifs', fake_plug_vifs)
2376
self.stubs.Set(self.libvirtconnection, '_create_image',
2378
self.stubs.Set(self.libvirtconnection, '_create_new_domain',
2379
fake_create_new_domain)
2380
self.stubs.Set(utils, 'execute', fake_execute)
2381
fw = base_firewall.NoopFirewallDriver()
2382
self.stubs.Set(self.libvirtconnection, 'firewall_driver', fw)
2384
ins_ref = self._create_instance()
2386
ref = self.libvirtconnection.finish_migration(
2387
context.get_admin_context(), None, ins_ref,
2388
disk_info_text, None, None, None)
2389
self.assertTrue(isinstance(ref, eventlet.event.Event))
2391
def test_finish_revert_migration(self):
2392
"""Test for nova.virt.libvirt.connection.LivirtConnection
2393
.finish_revert_migration. """
2395
def fake_execute(*args, **kwargs):
2398
def fake_plug_vifs(instance, network_info):
2401
def fake_create_new_domain(xml):
2404
self.stubs.Set(self.libvirtconnection, 'plug_vifs', fake_plug_vifs)
2405
self.stubs.Set(utils, 'execute', fake_execute)
2406
fw = base_firewall.NoopFirewallDriver()
2407
self.stubs.Set(self.libvirtconnection, 'firewall_driver', fw)
2408
self.stubs.Set(self.libvirtconnection, '_create_new_domain',
2409
fake_create_new_domain)
2411
with utils.tempdir() as tmpdir:
2412
self.flags(instances_path=tmpdir)
2413
ins_ref = self._create_instance()
2414
os.mkdir(os.path.join(tmpdir, ins_ref['name']))
2415
libvirt_xml_path = os.path.join(tmpdir,
2418
f = open(libvirt_xml_path, 'w')
2421
ref = self.libvirtconnection.finish_revert_migration(ins_ref, None)
2422
self.assertTrue(isinstance(ref, eventlet.event.Event))