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
libvirt_driver.disconnect_volume(connection_info, mount_device)
244
connection_info = vol_driver.terminate_connection(vol, self.connr)
246
def test_libvirt_lxc_volume(self):
247
self.stubs.Set(os.path, 'exists', lambda x: True)
248
vol_driver = volume_driver.ISCSIDriver()
249
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
250
location = '10.0.2.15:3260'
251
name = 'volume-00000001'
252
iqn = 'iqn.2010-10.org.openstack:%s' % name
255
'provider_auth': None,
256
'provider_location': '%s,fake %s' % (location, iqn)}
257
connection_info = vol_driver.initialize_connection(vol, self.connr)
259
xml = libvirt_driver.connect_volume(connection_info, mount_device)
260
tree = ElementTree.fromstring(xml)
261
dev_str = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-0' % (location, iqn)
262
self.assertEqual(tree.get('type'), 'block')
263
self.assertEqual(tree.find('./source').get('dev'), dev_str)
264
libvirt_driver.disconnect_volume(connection_info, mount_device)
265
connection_info = vol_driver.terminate_connection(vol, self.connr)
268
class CacheConcurrencyTestCase(test.TestCase):
270
super(CacheConcurrencyTestCase, self).setUp()
271
self.flags(instances_path='nova.compute.manager')
273
def fake_exists(fname):
274
basedir = os.path.join(FLAGS.instances_path, '_base')
279
def fake_execute(*args, **kwargs):
282
def fake_extend(image, size):
285
self.stubs.Set(os.path, 'exists', fake_exists)
286
self.stubs.Set(utils, 'execute', fake_execute)
287
self.stubs.Set(connection.disk, 'extend', fake_extend)
288
connection.libvirt_utils = fake_libvirt_utils
291
connection.libvirt_utils = libvirt_utils
292
super(CacheConcurrencyTestCase, self).tearDown()
294
def test_same_fname_concurrency(self):
295
"""Ensures that the same fname cache runs at a sequentially"""
296
conn = connection.LibvirtConnection
297
wait1 = eventlet.event.Event()
298
done1 = eventlet.event.Event()
299
eventlet.spawn(conn._cache_image, _concurrency,
300
'target', 'fname', False, None, wait1, done1)
301
wait2 = eventlet.event.Event()
302
done2 = eventlet.event.Event()
303
eventlet.spawn(conn._cache_image, _concurrency,
304
'target', 'fname', False, None, wait2, done2)
308
self.assertFalse(done2.ready())
313
self.assertTrue(done2.ready())
315
def test_different_fname_concurrency(self):
316
"""Ensures that two different fname caches are concurrent"""
317
conn = connection.LibvirtConnection
318
wait1 = eventlet.event.Event()
319
done1 = eventlet.event.Event()
320
eventlet.spawn(conn._cache_image, _concurrency,
321
'target', 'fname2', False, None, wait1, done1)
322
wait2 = eventlet.event.Event()
323
done2 = eventlet.event.Event()
324
eventlet.spawn(conn._cache_image, _concurrency,
325
'target', 'fname1', False, None, wait2, done2)
329
self.assertTrue(done2.ready())
335
class FakeVolumeDriver(object):
336
def __init__(self, *args, **kwargs):
339
def attach_volume(self, *args):
342
def detach_volume(self, *args):
345
def get_xml(self, *args):
349
def missing_libvirt():
350
return libvirt is None
353
class LibvirtConnTestCase(test.TestCase):
356
super(LibvirtConnTestCase, self).setUp()
357
connection._late_load_cheetah()
358
self.flags(fake_call=True)
359
self.user_id = 'fake'
360
self.project_id = 'fake'
361
self.context = context.get_admin_context()
362
self.flags(instances_path='')
363
self.call_libvirt_dependant_setup = False
364
connection.libvirt_utils = fake_libvirt_utils
366
def fake_extend(image, size):
369
self.stubs.Set(connection.disk, 'extend', fake_extend)
372
connection.libvirt_utils = libvirt_utils
373
super(LibvirtConnTestCase, self).tearDown()
375
test_instance = {'memory_kb': '1024000',
376
'basepath': '/some/path',
377
'bridge_name': 'br100',
379
'project_id': 'fake',
381
'image_ref': '155d900f-4e14-4e4c-a73d-069cbf4541e6',
384
'instance_type_id': '5'} # m1.small
386
def create_fake_libvirt_mock(self, **kwargs):
387
"""Defining mocks for LibvirtConnection(libvirt is not used)."""
389
# A fake libvirt.virConnect
390
class FakeLibvirtConnection(object):
391
def defineXML(self, xml):
392
return FakeVirtDomain()
395
volume_driver = 'iscsi=nova.tests.test_libvirt.FakeVolumeDriver'
396
self.flags(libvirt_volume_drivers=[volume_driver])
397
fake = FakeLibvirtConnection()
398
# Customizing above fake if necessary
399
for key, val in kwargs.items():
400
fake.__setattr__(key, val)
402
self.flags(image_service='nova.image.fake.FakeImageService')
403
self.flags(libvirt_vif_driver="nova.tests.fake_network.FakeVIFDriver")
405
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
406
connection.LibvirtConnection._conn = fake
408
def fake_lookup(self, instance_name):
409
return FakeVirtDomain()
411
def fake_execute(self, *args):
412
open(args[-1], "a").close()
414
def create_service(self, **kwargs):
415
service_ref = {'host': kwargs.get('host', 'dummy'),
416
'binary': 'nova-compute',
419
'availability_zone': 'zone'}
421
return db.service_create(context.get_admin_context(), service_ref)
423
def test_get_connector(self):
424
initiator = 'fake.initiator.iqn'
428
conn = connection.LibvirtConnection(True)
431
'initiator': initiator
436
result = conn.get_volume_connector(volume)
437
self.assertDictMatch(expected, result)
439
def test_preparing_xml_info(self):
440
conn = connection.LibvirtConnection(True)
441
instance_ref = db.instance_create(self.context, self.test_instance)
443
result = conn._prepare_xml_info(instance_ref,
444
_fake_network_info(self.stubs, 1),
446
self.assertTrue(len(result['nics']) == 1)
448
result = conn._prepare_xml_info(instance_ref,
449
_fake_network_info(self.stubs, 2),
451
self.assertTrue(len(result['nics']) == 2)
453
def test_xml_and_uri_no_ramdisk_no_kernel(self):
454
instance_data = dict(self.test_instance)
455
self._check_xml_and_uri(instance_data,
456
expect_kernel=False, expect_ramdisk=False)
458
def test_xml_and_uri_no_ramdisk(self):
459
instance_data = dict(self.test_instance)
460
instance_data['kernel_id'] = 'aki-deadbeef'
461
self._check_xml_and_uri(instance_data,
462
expect_kernel=True, expect_ramdisk=False)
464
def test_xml_and_uri_no_kernel(self):
465
instance_data = dict(self.test_instance)
466
instance_data['ramdisk_id'] = 'ari-deadbeef'
467
self._check_xml_and_uri(instance_data,
468
expect_kernel=False, expect_ramdisk=False)
470
def test_xml_and_uri(self):
471
instance_data = dict(self.test_instance)
472
instance_data['ramdisk_id'] = 'ari-deadbeef'
473
instance_data['kernel_id'] = 'aki-deadbeef'
474
self._check_xml_and_uri(instance_data,
475
expect_kernel=True, expect_ramdisk=True)
477
def test_xml_and_uri_rescue(self):
478
instance_data = dict(self.test_instance)
479
instance_data['ramdisk_id'] = 'ari-deadbeef'
480
instance_data['kernel_id'] = 'aki-deadbeef'
481
self._check_xml_and_uri(instance_data, expect_kernel=True,
482
expect_ramdisk=True, rescue=True)
484
def test_xml_uuid(self):
485
instance_data = dict(self.test_instance)
486
self._check_xml_and_uuid(instance_data)
488
def test_lxc_container_and_uri(self):
489
instance_data = dict(self.test_instance)
490
self._check_xml_and_container(instance_data)
492
def test_xml_disk_prefix(self):
493
instance_data = dict(self.test_instance)
494
self._check_xml_and_disk_prefix(instance_data)
496
def test_xml_disk_driver(self):
497
instance_data = dict(self.test_instance)
498
self._check_xml_and_disk_driver(instance_data)
500
def test_xml_disk_bus_virtio(self):
501
self._check_xml_and_disk_bus({"disk_format": "raw"},
504
def test_xml_disk_bus_ide(self):
505
self._check_xml_and_disk_bus({"disk_format": "iso"},
508
def test_list_instances(self):
509
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
510
connection.LibvirtConnection._conn.lookupByID = self.fake_lookup
511
connection.LibvirtConnection._conn.listDomainsID = lambda: [0, 1]
514
conn = connection.LibvirtConnection(False)
515
instances = conn.list_instances()
516
# Only one should be listed, since domain with ID 0 must be skiped
517
self.assertEquals(len(instances), 1)
519
def test_get_all_block_devices(self):
521
# NOTE(vish): id 0 is skipped
527
<source file='filename'/>
530
<source dev='/path/to/dev/1'/>
539
<source file='filename'/>
548
<source file='filename'/>
551
<source dev='/path/to/dev/3'/>
559
return FakeVirtDomain(xml[id])
561
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
562
connection.LibvirtConnection._conn.listDomainsID = lambda: range(4)
563
connection.LibvirtConnection._conn.lookupByID = fake_lookup
566
conn = connection.LibvirtConnection(False)
567
devices = conn.get_all_block_devices()
568
self.assertEqual(devices, ['/path/to/dev/1', '/path/to/dev/3'])
570
@test.skip_if(missing_libvirt(), "Test requires libvirt")
571
def test_snapshot_in_ami_format(self):
572
self.flags(image_service='nova.image.fake.FakeImageService')
575
image_service = utils.import_object(FLAGS.image_service)
577
# Assign different image_ref from nova/images/fakes for testing ami
578
test_instance = copy.deepcopy(self.test_instance)
579
test_instance["image_ref"] = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'
581
# Assuming that base image already exists in image_service
582
instance_ref = db.instance_create(self.context, test_instance)
583
properties = {'instance_id': instance_ref['id'],
584
'user_id': str(self.context.user_id)}
585
snapshot_name = 'test-snap'
586
sent_meta = {'name': snapshot_name, 'is_public': False,
587
'status': 'creating', 'properties': properties}
588
# Create new image. It will be updated in snapshot method
589
# To work with it from snapshot, the single image_service is needed
590
recv_meta = image_service.create(context, sent_meta)
592
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
593
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
594
self.mox.StubOutWithMock(connection.utils, 'execute')
595
connection.utils.execute = self.fake_execute
599
conn = connection.LibvirtConnection(False)
600
conn.snapshot(self.context, instance_ref, recv_meta['id'])
602
snapshot = image_service.show(context, recv_meta['id'])
603
self.assertEquals(snapshot['properties']['image_state'], 'available')
604
self.assertEquals(snapshot['status'], 'active')
605
self.assertEquals(snapshot['disk_format'], 'ami')
606
self.assertEquals(snapshot['name'], snapshot_name)
608
@test.skip_if(missing_libvirt(), "Test requires libvirt")
609
def test_snapshot_in_raw_format(self):
610
self.flags(image_service='nova.image.fake.FakeImageService')
613
image_service = utils.import_object(FLAGS.image_service)
615
# Assuming that base image already exists in image_service
616
instance_ref = db.instance_create(self.context, self.test_instance)
617
properties = {'instance_id': instance_ref['id'],
618
'user_id': str(self.context.user_id)}
619
snapshot_name = 'test-snap'
620
sent_meta = {'name': snapshot_name, 'is_public': False,
621
'status': 'creating', 'properties': properties}
622
# Create new image. It will be updated in snapshot method
623
# To work with it from snapshot, the single image_service is needed
624
recv_meta = image_service.create(context, sent_meta)
626
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
627
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
628
self.mox.StubOutWithMock(connection.utils, 'execute')
629
connection.utils.execute = self.fake_execute
633
conn = connection.LibvirtConnection(False)
634
conn.snapshot(self.context, instance_ref, recv_meta['id'])
636
snapshot = image_service.show(context, recv_meta['id'])
637
self.assertEquals(snapshot['properties']['image_state'], 'available')
638
self.assertEquals(snapshot['status'], 'active')
639
self.assertEquals(snapshot['disk_format'], 'raw')
640
self.assertEquals(snapshot['name'], snapshot_name)
642
@test.skip_if(missing_libvirt(), "Test requires libvirt")
643
def test_snapshot_in_qcow2_format(self):
644
self.flags(image_service='nova.image.fake.FakeImageService')
645
self.flags(snapshot_image_format='qcow2')
648
image_service = utils.import_object(FLAGS.image_service)
650
# Assuming that base image already exists in image_service
651
instance_ref = db.instance_create(self.context, self.test_instance)
652
properties = {'instance_id': instance_ref['id'],
653
'user_id': str(self.context.user_id)}
654
snapshot_name = 'test-snap'
655
sent_meta = {'name': snapshot_name, 'is_public': False,
656
'status': 'creating', 'properties': properties}
657
# Create new image. It will be updated in snapshot method
658
# To work with it from snapshot, the single image_service is needed
659
recv_meta = image_service.create(context, sent_meta)
661
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
662
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
663
self.mox.StubOutWithMock(connection.utils, 'execute')
664
connection.utils.execute = self.fake_execute
668
conn = connection.LibvirtConnection(False)
669
conn.snapshot(self.context, instance_ref, recv_meta['id'])
671
snapshot = image_service.show(context, recv_meta['id'])
672
self.assertEquals(snapshot['properties']['image_state'], 'available')
673
self.assertEquals(snapshot['status'], 'active')
674
self.assertEquals(snapshot['disk_format'], 'qcow2')
675
self.assertEquals(snapshot['name'], snapshot_name)
677
@test.skip_if(missing_libvirt(), "Test requires libvirt")
678
def test_snapshot_no_image_architecture(self):
679
self.flags(image_service='nova.image.fake.FakeImageService')
682
image_service = utils.import_object(FLAGS.image_service)
684
# Assign different image_ref from nova/images/fakes for
685
# testing different base image
686
test_instance = copy.deepcopy(self.test_instance)
687
test_instance["image_ref"] = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
689
# Assuming that base image already exists in image_service
690
instance_ref = db.instance_create(self.context, test_instance)
691
properties = {'instance_id': instance_ref['id'],
692
'user_id': str(self.context.user_id)}
693
snapshot_name = 'test-snap'
694
sent_meta = {'name': snapshot_name, 'is_public': False,
695
'status': 'creating', 'properties': properties}
696
# Create new image. It will be updated in snapshot method
697
# To work with it from snapshot, the single image_service is needed
698
recv_meta = image_service.create(context, sent_meta)
700
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
701
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
702
self.mox.StubOutWithMock(connection.utils, 'execute')
703
connection.utils.execute = self.fake_execute
707
conn = connection.LibvirtConnection(False)
708
conn.snapshot(self.context, instance_ref, recv_meta['id'])
710
snapshot = image_service.show(context, recv_meta['id'])
711
self.assertEquals(snapshot['properties']['image_state'], 'available')
712
self.assertEquals(snapshot['status'], 'active')
713
self.assertEquals(snapshot['name'], snapshot_name)
715
@test.skip_if(missing_libvirt(), "Test requires libvirt")
716
def test_snapshot_no_original_image(self):
717
self.flags(image_service='nova.image.fake.FakeImageService')
720
image_service = utils.import_object(FLAGS.image_service)
722
# Assign a non-existent image
723
test_instance = copy.deepcopy(self.test_instance)
724
test_instance["image_ref"] = '661122aa-1234-dede-fefe-babababababa'
726
instance_ref = db.instance_create(self.context, test_instance)
727
properties = {'instance_id': instance_ref['id'],
728
'user_id': str(self.context.user_id)}
729
snapshot_name = 'test-snap'
730
sent_meta = {'name': snapshot_name, 'is_public': False,
731
'status': 'creating', 'properties': properties}
732
recv_meta = image_service.create(context, sent_meta)
734
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
735
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
736
self.mox.StubOutWithMock(connection.utils, 'execute')
737
connection.utils.execute = self.fake_execute
741
conn = connection.LibvirtConnection(False)
742
conn.snapshot(self.context, instance_ref, recv_meta['id'])
744
snapshot = image_service.show(context, recv_meta['id'])
745
self.assertEquals(snapshot['properties']['image_state'], 'available')
746
self.assertEquals(snapshot['status'], 'active')
747
self.assertEquals(snapshot['name'], snapshot_name)
749
def test_attach_invalid_volume_type(self):
750
self.create_fake_libvirt_mock()
751
connection.LibvirtConnection._conn.lookupByName = self.fake_lookup
753
conn = connection.LibvirtConnection(False)
754
self.assertRaises(exception.VolumeDriverNotFound,
756
{"driver_volume_type": "badtype"},
760
def test_multi_nic(self):
761
instance_data = dict(self.test_instance)
762
network_info = _fake_network_info(self.stubs, 2)
763
conn = connection.LibvirtConnection(True)
764
instance_ref = db.instance_create(self.context, instance_data)
765
xml = conn.to_xml(instance_ref, network_info, None, False)
766
tree = ElementTree.fromstring(xml)
767
interfaces = tree.findall("./devices/interface")
768
self.assertEquals(len(interfaces), 2)
769
parameters = interfaces[0].findall('./filterref/parameter')
770
self.assertEquals(interfaces[0].get('type'), 'bridge')
771
self.assertEquals(parameters[0].get('name'), 'IP')
772
self.assertTrue(_ipv4_like(parameters[0].get('value'), '192.168'))
773
self.assertEquals(parameters[1].get('name'), 'DHCPSERVER')
774
self.assertTrue(_ipv4_like(parameters[1].get('value'), '192.168.*.1'))
776
def _check_xml_and_container(self, instance):
777
user_context = context.RequestContext(self.user_id,
779
instance_ref = db.instance_create(user_context, instance)
781
self.flags(libvirt_type='lxc')
782
conn = connection.LibvirtConnection(True)
784
self.assertEquals(conn.uri, 'lxc:///')
786
network_info = _fake_network_info(self.stubs, 1)
787
xml = conn.to_xml(instance_ref, network_info)
788
tree = ElementTree.fromstring(xml)
791
(lambda t: t.find('.').get('type'), 'lxc'),
792
(lambda t: t.find('./os/type').text, 'exe'),
793
(lambda t: t.find('./devices/filesystem/target').get('dir'), '/')]
795
for i, (check, expected_result) in enumerate(check):
796
self.assertEqual(check(tree),
798
'%s failed common check %d' % (xml, i))
800
target = tree.find('./devices/filesystem/source').get('dir')
801
self.assertTrue(len(target) > 0)
803
def _check_xml_and_disk_prefix(self, instance):
804
user_context = context.RequestContext(self.user_id,
806
instance_ref = db.instance_create(user_context, instance)
810
(lambda t: t.find('.').get('type'), 'qemu'),
811
(lambda t: t.find('./devices/disk/target').get('dev'), 'vda')],
813
(lambda t: t.find('.').get('type'), 'xen'),
814
(lambda t: t.find('./devices/disk/target').get('dev'), 'sda')],
816
(lambda t: t.find('.').get('type'), 'kvm'),
817
(lambda t: t.find('./devices/disk/target').get('dev'), 'vda')],
819
(lambda t: t.find('.').get('type'), 'uml'),
820
(lambda t: t.find('./devices/disk/target').get('dev'), 'ubda')]
823
for (libvirt_type, checks) in type_disk_map.iteritems():
824
self.flags(libvirt_type=libvirt_type)
825
conn = connection.LibvirtConnection(True)
827
network_info = _fake_network_info(self.stubs, 1)
828
xml = conn.to_xml(instance_ref, network_info)
829
tree = ElementTree.fromstring(xml)
831
for i, (check, expected_result) in enumerate(checks):
832
self.assertEqual(check(tree),
834
'%s != %s failed check %d' %
835
(check(tree), expected_result, i))
837
def _check_xml_and_disk_driver(self, image_meta):
839
directio_supported = True
841
def os_open_stub(path, flags, *args, **kwargs):
842
if flags & os.O_DIRECT:
843
if not directio_supported:
844
raise OSError(errno.EINVAL,
845
'%s: %s' % (os.strerror(errno.EINVAL), path))
846
flags &= ~os.O_DIRECT
847
return os_open(path, flags, *args, **kwargs)
849
self.stubs.Set(os, 'open', os_open_stub)
851
user_context = context.RequestContext(self.user_id, self.project_id)
852
instance_ref = db.instance_create(user_context, self.test_instance)
853
network_info = _fake_network_info(self.stubs, 1)
855
xml = connection.LibvirtConnection(True).to_xml(instance_ref,
858
tree = ElementTree.fromstring(xml)
859
disks = tree.findall('./devices/disk/driver')
861
self.assertEqual(disk.get("cache"), "none")
863
directio_supported = False
865
# The O_DIRECT availability is cached on first use in
866
# LibvirtConnection, hence we re-create it here
867
xml = connection.LibvirtConnection(True).to_xml(instance_ref,
870
tree = ElementTree.fromstring(xml)
871
disks = tree.findall('./devices/disk/driver')
873
self.assertEqual(disk.get("cache"), "writethrough")
875
def _check_xml_and_disk_bus(self, image_meta, device_type, bus):
876
user_context = context.RequestContext(self.user_id, self.project_id)
877
instance_ref = db.instance_create(user_context, self.test_instance)
878
network_info = _fake_network_info(self.stubs, 1)
880
xml = connection.LibvirtConnection(True).to_xml(instance_ref,
883
tree = ElementTree.fromstring(xml)
884
self.assertEqual(tree.find('./devices/disk').get('device'),
886
self.assertEqual(tree.find('./devices/disk/target').get('bus'), bus)
888
def _check_xml_and_uuid(self, image_meta):
889
user_context = context.RequestContext(self.user_id, self.project_id)
890
instance_ref = db.instance_create(user_context, self.test_instance)
891
network_info = _fake_network_info(self.stubs, 1)
893
xml = connection.LibvirtConnection(True).to_xml(instance_ref,
896
tree = ElementTree.fromstring(xml)
897
self.assertEqual(tree.find('./uuid').text,
898
instance_ref['uuid'])
900
def _check_xml_and_uri(self, instance, expect_ramdisk, expect_kernel,
902
user_context = context.RequestContext(self.user_id, self.project_id)
903
instance_ref = db.instance_create(user_context, instance)
904
network_ref = db.project_get_networks(context.get_admin_context(),
907
type_uri_map = {'qemu': ('qemu:///system',
908
[(lambda t: t.find('.').get('type'), 'qemu'),
909
(lambda t: t.find('./os/type').text, 'hvm'),
910
(lambda t: t.find('./devices/emulator'), None)]),
911
'kvm': ('qemu:///system',
912
[(lambda t: t.find('.').get('type'), 'kvm'),
913
(lambda t: t.find('./os/type').text, 'hvm'),
914
(lambda t: t.find('./devices/emulator'), None)]),
915
'uml': ('uml:///system',
916
[(lambda t: t.find('.').get('type'), 'uml'),
917
(lambda t: t.find('./os/type').text, 'uml')]),
919
[(lambda t: t.find('.').get('type'), 'xen'),
920
(lambda t: t.find('./os/type').text, 'linux')]),
923
for hypervisor_type in ['qemu', 'kvm', 'xen']:
924
check_list = type_uri_map[hypervisor_type][1]
927
check = (lambda t: t.find('./os/kernel').text.split('/')[1],
929
check_list.append(check)
930
check = (lambda t: t.find('./os/initrd').text.split('/')[1],
932
check_list.append(check)
935
check = (lambda t: t.find('./os/kernel').text.split(
938
check = (lambda t: t.find('./os/kernel'), None)
939
check_list.append(check)
942
check = (lambda t: t.find('./os/initrd').text.split(
945
check = (lambda t: t.find('./os/initrd'), None)
946
check_list.append(check)
948
if hypervisor_type in ['qemu', 'kvm']:
949
check = (lambda t: t.findall('./devices/serial')[0].get(
951
check_list.append(check)
952
check = (lambda t: t.findall('./devices/serial')[1].get(
954
check_list.append(check)
955
check = (lambda t: t.findall('./devices/serial/source')[0].get(
956
'path').split('/')[1], 'console.log')
957
check_list.append(check)
959
check = (lambda t: t.find('./devices/console').get(
961
check_list.append(check)
963
parameter = './devices/interface/filterref/parameter'
965
(lambda t: t.find('.').tag, 'domain'),
966
(lambda t: t.find(parameter).get('name'), 'IP'),
967
(lambda t: _ipv4_like(t.find(parameter).get('value'), '192.168'),
969
(lambda t: t.findall(parameter)[1].get('name'), 'DHCPSERVER'),
970
(lambda t: _ipv4_like(t.findall(parameter)[1].get('value'),
971
'192.168.*.1'), True),
972
(lambda t: t.find('./memory').text, '2097152')]
975
(lambda t: t.findall('./devices/disk/source')[0].get(
976
'file').split('/')[1], 'disk.rescue'),
977
(lambda t: t.findall('./devices/disk/source')[1].get(
978
'file').split('/')[1], 'disk')]
980
common_checks += [(lambda t: t.findall(
981
'./devices/disk/source')[0].get('file').split('/')[1],
983
common_checks += [(lambda t: t.findall(
984
'./devices/disk/source')[1].get('file').split('/')[1],
987
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
988
self.flags(libvirt_type=libvirt_type)
989
conn = connection.LibvirtConnection(True)
991
self.assertEquals(conn.uri, expected_uri)
993
network_info = _fake_network_info(self.stubs, 1)
994
xml = conn.to_xml(instance_ref, network_info, None, rescue)
995
tree = ElementTree.fromstring(xml)
996
for i, (check, expected_result) in enumerate(checks):
997
self.assertEqual(check(tree),
999
'%s != %s failed check %d' %
1000
(check(tree), expected_result, i))
1002
for i, (check, expected_result) in enumerate(common_checks):
1003
self.assertEqual(check(tree),
1005
'%s != %s failed common check %d' %
1006
(check(tree), expected_result, i))
1008
# This test is supposed to make sure we don't
1009
# override a specifically set uri
1011
# Deliberately not just assigning this string to FLAGS.libvirt_uri and
1012
# checking against that later on. This way we make sure the
1013
# implementation doesn't fiddle around with the FLAGS.
1014
testuri = 'something completely different'
1015
self.flags(libvirt_uri=testuri)
1016
for (libvirt_type, (expected_uri, checks)) in type_uri_map.iteritems():
1017
self.flags(libvirt_type=libvirt_type)
1018
conn = connection.LibvirtConnection(True)
1019
self.assertEquals(conn.uri, testuri)
1020
db.instance_destroy(user_context, instance_ref['id'])
1022
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1023
def test_ensure_filtering_rules_for_instance_timeout(self):
1024
"""ensure_filtering_fules_for_instance() finishes with timeout."""
1026
def fake_none(self, *args):
1029
def fake_raise(self):
1030
raise libvirt.libvirtError('ERR')
1032
class FakeTime(object):
1039
fake_timer = FakeTime()
1041
# _fake_network_info must be called before create_fake_libvirt_mock(),
1042
# as _fake_network_info calls utils.import_class() and
1043
# create_fake_libvirt_mock() mocks utils.import_class().
1044
network_info = _fake_network_info(self.stubs, 1)
1045
self.create_fake_libvirt_mock()
1046
instance_ref = db.instance_create(self.context, self.test_instance)
1049
self.mox.ReplayAll()
1051
conn = connection.LibvirtConnection(False)
1052
self.stubs.Set(conn.firewall_driver,
1053
'setup_basic_filtering',
1055
self.stubs.Set(conn.firewall_driver,
1056
'prepare_instance_filter',
1058
self.stubs.Set(conn.firewall_driver,
1059
'instance_filter_exists',
1061
conn.ensure_filtering_rules_for_instance(instance_ref,
1064
except exception.Error, e:
1065
c1 = (0 <= e.message.find('Timeout migrating for'))
1068
self.assertEqual(29, fake_timer.counter, "Didn't wait the expected "
1071
db.instance_destroy(self.context, instance_ref['id'])
1073
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1074
def test_live_migration_raises_exception(self):
1075
"""Confirms recover method is called when exceptions are raised."""
1077
self.compute = utils.import_object(FLAGS.compute_manager)
1078
instance_dict = {'host': 'fake',
1079
'power_state': power_state.RUNNING,
1080
'vm_state': vm_states.ACTIVE}
1081
instance_ref = db.instance_create(self.context, self.test_instance)
1082
instance_ref = db.instance_update(self.context, instance_ref['id'],
1084
vol_dict = {'status': 'migrating', 'size': 1}
1085
volume_ref = db.volume_create(self.context, vol_dict)
1086
db.volume_attached(self.context, volume_ref['id'], instance_ref['id'],
1090
vdmock = self.mox.CreateMock(libvirt.virDomain)
1091
self.mox.StubOutWithMock(vdmock, "migrateToURI")
1092
_bandwidth = FLAGS.live_migration_bandwidth
1093
vdmock.migrateToURI(FLAGS.live_migration_uri % 'dest',
1096
_bandwidth).AndRaise(libvirt.libvirtError('ERR'))
1098
def fake_lookup(instance_name):
1099
if instance_name == instance_ref.name:
1102
self.create_fake_libvirt_mock(lookupByName=fake_lookup)
1103
self.mox.StubOutWithMock(self.compute, "rollback_live_migration")
1104
self.compute.rollback_live_migration(self.context, instance_ref,
1108
self.mox.ReplayAll()
1109
conn = connection.LibvirtConnection(False)
1110
self.assertRaises(libvirt.libvirtError,
1111
conn._live_migration,
1112
self.context, instance_ref, 'dest', False,
1113
self.compute.rollback_live_migration)
1115
instance_ref = db.instance_get(self.context, instance_ref['id'])
1116
self.assertTrue(instance_ref['vm_state'] == vm_states.ACTIVE)
1117
self.assertTrue(instance_ref['power_state'] == power_state.RUNNING)
1118
volume_ref = db.volume_get(self.context, volume_ref['id'])
1119
self.assertTrue(volume_ref['status'] == 'in-use')
1121
db.volume_destroy(self.context, volume_ref['id'])
1122
db.instance_destroy(self.context, instance_ref['id'])
1124
def test_pre_live_migration_works_correctly(self):
1125
"""Confirms pre_block_migration works correctly."""
1127
vol = {'block_device_mapping': [
1128
{'connection_info': 'dummy', 'mount_device': '/dev/sda'},
1129
{'connection_info': 'dummy', 'mount_device': '/dev/sdb'}]}
1130
conn = connection.LibvirtConnection(False)
1133
self.mox.StubOutWithMock(driver, "block_device_info_get_mapping")
1134
driver.block_device_info_get_mapping(vol
1135
).AndReturn(vol['block_device_mapping'])
1136
self.mox.StubOutWithMock(conn, "volume_driver_method")
1137
for v in vol['block_device_mapping']:
1138
conn.volume_driver_method('connect_volume',
1139
v['connection_info'], v['mount_device'])
1142
self.mox.ReplayAll()
1143
self.assertEqual(conn.pre_live_migration(vol), None)
1145
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1146
def test_pre_block_migration_works_correctly(self):
1147
"""Confirms pre_block_migration works correctly."""
1148
# Replace instances_path since this testcase creates tmpfile
1149
with utils.tempdir() as tmpdir:
1150
self.flags(instances_path=tmpdir)
1153
instance_ref = db.instance_create(self.context, self.test_instance)
1154
dummyjson = ('[{"path": "%s/disk", "disk_size": "10737418240",'
1155
' "type": "raw", "backing_file": ""}]')
1158
# qemu-img should be mockd since test environment might not have
1160
self.mox.ReplayAll()
1161
conn = connection.LibvirtConnection(False)
1162
conn.pre_block_migration(self.context, instance_ref,
1165
self.assertTrue(os.path.exists('%s/%s/' %
1166
(tmpdir, instance_ref.name)))
1168
db.instance_destroy(self.context, instance_ref['id'])
1170
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1171
def test_get_instance_disk_info_works_correctly(self):
1172
"""Confirms pre_block_migration works correctly."""
1174
instance_ref = db.instance_create(self.context, self.test_instance)
1175
dummyxml = ("<domain type='kvm'><name>instance-0000000a</name>"
1177
"<disk type='file'><driver name='qemu' type='raw'/>"
1178
"<source file='/test/disk'/>"
1179
"<target dev='vda' bus='virtio'/></disk>"
1180
"<disk type='file'><driver name='qemu' type='qcow2'/>"
1181
"<source file='/test/disk.local'/>"
1182
"<target dev='vdb' bus='virtio'/></disk>"
1183
"</devices></domain>")
1185
ret = ("image: /test/disk\n"
1186
"file format: raw\n"
1187
"virtual size: 20G (21474836480 bytes)\n"
1189
"cluster_size: 2097152\n"
1190
"backing file: /test/dummy (actual path: /backing/file)\n")
1193
vdmock = self.mox.CreateMock(libvirt.virDomain)
1194
self.mox.StubOutWithMock(vdmock, "XMLDesc")
1195
vdmock.XMLDesc(0).AndReturn(dummyxml)
1197
def fake_lookup(instance_name):
1198
if instance_name == instance_ref.name:
1200
self.create_fake_libvirt_mock(lookupByName=fake_lookup)
1202
GB = 1024 * 1024 * 1024
1203
fake_libvirt_utils.disk_sizes['/test/disk'] = 10 * GB
1204
fake_libvirt_utils.disk_sizes['/test/disk.local'] = 20 * GB
1205
fake_libvirt_utils.disk_backing_files['/test/disk.local'] = 'file'
1207
self.mox.StubOutWithMock(os.path, "getsize")
1208
os.path.getsize('/test/disk').AndReturn((10737418240))
1210
self.mox.StubOutWithMock(utils, "execute")
1211
utils.execute('qemu-img', 'info',
1212
'/test/disk.local').AndReturn((ret, ''))
1214
os.path.getsize('/test/disk.local').AndReturn((21474836480))
1216
self.mox.ReplayAll()
1217
conn = connection.LibvirtConnection(False)
1218
info = conn.get_instance_disk_info(instance_ref.name)
1219
info = utils.loads(info)
1220
self.assertEquals(info[0]['type'], 'raw')
1221
self.assertEquals(info[0]['path'], '/test/disk')
1222
self.assertEquals(info[0]['disk_size'], 10737418240)
1223
self.assertEquals(info[0]['backing_file'], "")
1224
self.assertEquals(info[1]['type'], 'qcow2')
1225
self.assertEquals(info[1]['path'], '/test/disk.local')
1226
self.assertEquals(info[1]['virt_disk_size'], 21474836480)
1227
self.assertEquals(info[1]['backing_file'], "file")
1229
db.instance_destroy(self.context, instance_ref['id'])
1231
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1232
def test_spawn_with_network_info(self):
1234
def fake_none(self, instance):
1237
# _fake_network_info must be called before create_fake_libvirt_mock(),
1238
# as _fake_network_info calls utils.import_class() and
1239
# create_fake_libvirt_mock() mocks utils.import_class().
1240
network_info = _fake_network_info(self.stubs, 1)
1241
self.create_fake_libvirt_mock()
1243
instance_ref = self.test_instance
1244
instance_ref['image_ref'] = 123456 # we send an int to test sha1 call
1245
instance = db.instance_create(self.context, instance_ref)
1248
self.mox.ReplayAll()
1249
conn = connection.LibvirtConnection(False)
1250
self.stubs.Set(conn.firewall_driver,
1251
'setup_basic_filtering',
1253
self.stubs.Set(conn.firewall_driver,
1254
'prepare_instance_filter',
1258
conn.spawn(self.context, instance, None, network_info)
1259
except Exception, e:
1260
# assert that no exception is raised due to sha1 receiving an int
1261
self.assertEqual(-1, str(e.message).find('must be string or buffer'
1263
count = (0 <= str(e.message).find('Unexpected method call'))
1265
path = os.path.join(FLAGS.instances_path, instance.name)
1266
if os.path.isdir(path):
1269
path = os.path.join(FLAGS.instances_path, '_base')
1270
if os.path.isdir(path):
1271
shutil.rmtree(os.path.join(FLAGS.instances_path, '_base'))
1273
def test_get_host_ip_addr(self):
1274
conn = connection.LibvirtConnection(False)
1275
ip = conn.get_host_ip_addr()
1276
self.assertEquals(ip, FLAGS.my_ip)
1278
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1279
def test_broken_connection(self):
1280
for (error, domain) in (
1281
(libvirt.VIR_ERR_SYSTEM_ERROR, libvirt.VIR_FROM_REMOTE),
1282
(libvirt.VIR_ERR_SYSTEM_ERROR, libvirt.VIR_FROM_RPC)):
1284
conn = connection.LibvirtConnection(False)
1286
self.mox.StubOutWithMock(conn, "_wrapped_conn")
1287
self.mox.StubOutWithMock(conn._wrapped_conn, "getCapabilities")
1288
self.mox.StubOutWithMock(libvirt.libvirtError, "get_error_code")
1289
self.mox.StubOutWithMock(libvirt.libvirtError, "get_error_domain")
1291
conn._wrapped_conn.getCapabilities().AndRaise(
1292
libvirt.libvirtError("fake failure"))
1294
libvirt.libvirtError.get_error_code().AndReturn(error)
1295
libvirt.libvirtError.get_error_domain().AndReturn(domain)
1297
self.mox.ReplayAll()
1299
self.assertFalse(conn._test_connection())
1301
self.mox.UnsetStubs()
1303
def test_volume_in_mapping(self):
1304
conn = connection.LibvirtConnection(False)
1305
swap = {'device_name': '/dev/sdb',
1307
ephemerals = [{'num': 0,
1308
'virtual_name': 'ephemeral0',
1309
'device_name': '/dev/sdc1',
1312
'virtual_name': 'ephemeral2',
1313
'device_name': '/dev/sdd',
1315
block_device_mapping = [{'mount_device': '/dev/sde',
1316
'device_path': 'fake_device'},
1317
{'mount_device': '/dev/sdf',
1318
'device_path': 'fake_device'}]
1319
block_device_info = {
1320
'root_device_name': '/dev/sda',
1322
'ephemerals': ephemerals,
1323
'block_device_mapping': block_device_mapping}
1325
def _assert_volume_in_mapping(device_name, true_or_false):
1326
self.assertEquals(conn._volume_in_mapping(device_name,
1330
_assert_volume_in_mapping('sda', False)
1331
_assert_volume_in_mapping('sdb', True)
1332
_assert_volume_in_mapping('sdc1', True)
1333
_assert_volume_in_mapping('sdd', True)
1334
_assert_volume_in_mapping('sde', True)
1335
_assert_volume_in_mapping('sdf', True)
1336
_assert_volume_in_mapping('sdg', False)
1337
_assert_volume_in_mapping('sdh1', False)
1339
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1340
def test_immediate_delete(self):
1341
conn = connection.LibvirtConnection(False)
1342
self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn')
1343
connection.LibvirtConnection._conn.lookupByName = lambda x: None
1345
instance = db.instance_create(self.context, self.test_instance)
1346
conn.destroy(instance, {})
1348
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1349
def test_destroy_saved(self):
1350
"""Ensure destroy calls managedSaveRemove for saved instance"""
1351
mock = self.mox.CreateMock(libvirt.virDomain)
1353
mock.hasManagedSaveImage(0).AndReturn(1)
1354
mock.managedSaveRemove(0)
1357
self.mox.ReplayAll()
1359
def fake_lookup_by_name(instance_name):
1362
conn = connection.LibvirtConnection(False)
1363
self.stubs.Set(conn, '_lookup_by_name', fake_lookup_by_name)
1364
instance = {"name": "instancename", "id": "instanceid",
1365
"uuid": "875a8070-d0b9-4949-8b31-104d125c9a64"}
1366
conn.destroy(instance, [])
1368
def test_available_least_handles_missing(self):
1369
"""Ensure destroy calls managedSaveRemove for saved instance"""
1370
conn = connection.LibvirtConnection(False)
1372
def list_instances():
1374
self.stubs.Set(conn, 'list_instances', list_instances)
1376
def get_info(instance_name):
1377
raise exception.InstanceNotFound()
1378
self.stubs.Set(conn, 'get_instance_disk_info', get_info)
1380
result = conn.get_disk_available_least()
1381
space = fake_libvirt_utils.get_fs_info(FLAGS.instances_path)['free']
1382
self.assertEqual(result, space / 1024 ** 3)
1385
class HostStateTestCase(test.TestCase):
1387
cpu_info = ('{"vendor": "Intel", "model": "pentium", "arch": "i686", '
1388
'"features": ["ssse3", "monitor", "pni", "sse2", "sse", '
1389
'"fxsr", "clflush", "pse36", "pat", "cmov", "mca", "pge", '
1390
'"mtrr", "sep", "apic"], '
1391
'"topology": {"cores": "1", "threads": "1", "sockets": "1"}}')
1393
class FakeConnection(object):
1394
"""Fake connection object"""
1396
def get_vcpu_total(self):
1399
def get_vcpu_used(self):
1402
def get_cpu_info(self):
1403
return HostStateTestCase.cpu_info
1405
def get_local_gb_total(self):
1408
def get_local_gb_used(self):
1411
def get_memory_mb_total(self):
1414
def get_memory_mb_used(self):
1417
def get_hypervisor_type(self):
1420
def get_hypervisor_version(self):
1423
def get_disk_available_least(self):
1426
def test_update_status(self):
1427
self.mox.StubOutWithMock(connection, 'get_connection')
1428
connection.get_connection(True).AndReturn(self.FakeConnection())
1430
self.mox.ReplayAll()
1431
hs = connection.HostState(True)
1433
self.assertEquals(stats["vcpus"], 1)
1434
self.assertEquals(stats["vcpus_used"], 0)
1435
self.assertEquals(stats["cpu_info"],
1436
{"vendor": "Intel", "model": "pentium", "arch": "i686",
1437
"features": ["ssse3", "monitor", "pni", "sse2", "sse",
1438
"fxsr", "clflush", "pse36", "pat", "cmov",
1439
"mca", "pge", "mtrr", "sep", "apic"],
1440
"topology": {"cores": "1", "threads": "1", "sockets": "1"}
1442
self.assertEquals(stats["disk_total"], 100)
1443
self.assertEquals(stats["disk_used"], 20)
1444
self.assertEquals(stats["disk_available"], 80)
1445
self.assertEquals(stats["host_memory_total"], 497)
1446
self.assertEquals(stats["host_memory_free"], 409)
1447
self.assertEquals(stats["hypervisor_type"], 'QEMU')
1448
self.assertEquals(stats["hypervisor_version"], 13091)
1451
class NWFilterFakes:
1455
def nwfilterLookupByName(self, name):
1456
if name in self.filters:
1457
return self.filters[name]
1458
raise libvirt.libvirtError('Filter Not Found')
1460
def filterDefineXMLMock(self, xml):
1461
class FakeNWFilterInternal:
1462
def __init__(self, parent, name):
1464
self.parent = parent
1467
del self.parent.filters[self.name]
1469
tree = ElementTree.fromstring(xml)
1470
name = tree.get('name')
1471
if name not in self.filters:
1472
self.filters[name] = FakeNWFilterInternal(self, name)
1476
class IptablesFirewallTestCase(test.TestCase):
1478
super(IptablesFirewallTestCase, self).setUp()
1480
self.user_id = 'fake'
1481
self.project_id = 'fake'
1482
self.context = context.RequestContext(self.user_id, self.project_id)
1484
class FakeLibvirtConnection(object):
1485
def nwfilterDefineXML(*args, **kwargs):
1486
"""setup_basic_rules in nwfilter calls this."""
1488
self.fake_libvirt_connection = FakeLibvirtConnection()
1489
self.fw = firewall.IptablesFirewallDriver(
1490
get_connection=lambda: self.fake_libvirt_connection)
1493
'# Generated by iptables-save v1.4.10 on Sat Feb 19 00:03:19 2011',
1495
':PREROUTING ACCEPT [1170:189210]',
1496
':INPUT ACCEPT [844:71028]',
1497
':OUTPUT ACCEPT [5149:405186]',
1498
':POSTROUTING ACCEPT [5063:386098]',
1502
'# Generated by iptables-save v1.4.4 on Mon Dec 6 11:54:13 2010',
1504
':INPUT ACCEPT [969615:281627771]',
1505
':FORWARD ACCEPT [0:0]',
1506
':OUTPUT ACCEPT [915599:63811649]',
1507
':nova-block-ipv4 - [0:0]',
1508
'-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT ',
1509
'-A FORWARD -d 192.168.122.0/24 -o virbr0 -m state --state RELATED'
1510
',ESTABLISHED -j ACCEPT ',
1511
'-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT ',
1512
'-A FORWARD -i virbr0 -o virbr0 -j ACCEPT ',
1513
'-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable ',
1514
'-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable ',
1516
'# Completed on Mon Dec 6 11:54:13 2010',
1519
in6_filter_rules = [
1520
'# Generated by ip6tables-save v1.4.4 on Tue Jan 18 23:47:56 2011',
1522
':INPUT ACCEPT [349155:75810423]',
1523
':FORWARD ACCEPT [0:0]',
1524
':OUTPUT ACCEPT [349256:75777230]',
1526
'# Completed on Tue Jan 18 23:47:56 2011',
1529
def _create_instance_ref(self):
1530
return db.instance_create(self.context,
1532
'project_id': 'fake',
1533
'instance_type_id': 1})
1535
def test_static_filters(self):
1536
instance_ref = self._create_instance_ref()
1537
src_instance_ref = self._create_instance_ref()
1539
admin_ctxt = context.get_admin_context()
1540
secgroup = db.security_group_create(admin_ctxt,
1542
'project_id': 'fake',
1543
'name': 'testgroup',
1544
'description': 'test group'})
1546
src_secgroup = db.security_group_create(admin_ctxt,
1548
'project_id': 'fake',
1549
'name': 'testsourcegroup',
1550
'description': 'src group'})
1552
db.security_group_rule_create(admin_ctxt,
1553
{'parent_group_id': secgroup['id'],
1557
'cidr': '192.168.11.0/24'})
1559
db.security_group_rule_create(admin_ctxt,
1560
{'parent_group_id': secgroup['id'],
1564
'cidr': '192.168.11.0/24'})
1566
db.security_group_rule_create(admin_ctxt,
1567
{'parent_group_id': secgroup['id'],
1571
'cidr': '192.168.10.0/24'})
1573
db.security_group_rule_create(admin_ctxt,
1574
{'parent_group_id': secgroup['id'],
1578
'group_id': src_secgroup['id']})
1580
db.instance_add_security_group(admin_ctxt, instance_ref['uuid'],
1582
db.instance_add_security_group(admin_ctxt, src_instance_ref['uuid'],
1584
instance_ref = db.instance_get(admin_ctxt, instance_ref['id'])
1585
src_instance_ref = db.instance_get(admin_ctxt, src_instance_ref['id'])
1587
# self.fw.add_instance(instance_ref)
1588
def fake_iptables_execute(*cmd, **kwargs):
1589
process_input = kwargs.get('process_input', None)
1590
if cmd == ('ip6tables-save', '-t', 'filter'):
1591
return '\n'.join(self.in6_filter_rules), None
1592
if cmd == ('iptables-save', '-t', 'filter'):
1593
return '\n'.join(self.in_filter_rules), None
1594
if cmd == ('iptables-save', '-t', 'nat'):
1595
return '\n'.join(self.in_nat_rules), None
1596
if cmd == ('iptables-restore',):
1597
lines = process_input.split('\n')
1598
if '*filter' in lines:
1599
self.out_rules = lines
1601
if cmd == ('ip6tables-restore',):
1602
lines = process_input.split('\n')
1603
if '*filter' in lines:
1604
self.out6_rules = lines
1608
network_model = _fake_network_info(self.stubs, 1, spectacular=True)
1610
from nova.network import linux_net
1611
linux_net.iptables_manager.execute = fake_iptables_execute
1613
_fake_stub_out_get_nw_info(self.stubs, lambda *a, **kw: network_model)
1615
network_info = compute_utils.legacy_network_info(network_model)
1616
self.fw.prepare_instance_filter(instance_ref, network_info)
1617
self.fw.apply_instance_filter(instance_ref, network_info)
1619
in_rules = filter(lambda l: not l.startswith('#'),
1620
self.in_filter_rules)
1621
for rule in in_rules:
1622
if not 'nova' in rule:
1623
self.assertTrue(rule in self.out_rules,
1624
'Rule went missing: %s' % rule)
1626
instance_chain = None
1627
for rule in self.out_rules:
1628
# This is pretty crude, but it'll do for now
1629
# last two octets change
1630
if re.search('-d 192.168.[0-9]{1,3}.[0-9]{1,3} -j', rule):
1631
instance_chain = rule.split(' ')[-1]
1633
self.assertTrue(instance_chain, "The instance chain wasn't added")
1635
security_group_chain = None
1636
for rule in self.out_rules:
1637
# This is pretty crude, but it'll do for now
1638
if '-A %s -j' % instance_chain in rule:
1639
security_group_chain = rule.split(' ')[-1]
1641
self.assertTrue(security_group_chain,
1642
"The security group chain wasn't added")
1644
regex = re.compile('-A .* -j ACCEPT -p icmp -s 192.168.11.0/24')
1645
self.assertTrue(len(filter(regex.match, self.out_rules)) > 0,
1646
"ICMP acceptance rule wasn't added")
1648
regex = re.compile('-A .* -j ACCEPT -p icmp -m icmp --icmp-type 8'
1649
' -s 192.168.11.0/24')
1650
self.assertTrue(len(filter(regex.match, self.out_rules)) > 0,
1651
"ICMP Echo Request acceptance rule wasn't added")
1653
for ip in network_model.fixed_ips():
1654
if ip['version'] != 4:
1656
regex = re.compile('-A .* -j ACCEPT -p tcp -m multiport '
1657
'--dports 80:81 -s %s' % ip['address'])
1658
self.assertTrue(len(filter(regex.match, self.out_rules)) > 0,
1659
"TCP port 80/81 acceptance rule wasn't added")
1661
regex = re.compile('-A .* -j ACCEPT -p tcp '
1662
'-m multiport --dports 80:81 -s 192.168.10.0/24')
1663
self.assertTrue(len(filter(regex.match, self.out_rules)) > 0,
1664
"TCP port 80/81 acceptance rule wasn't added")
1665
db.instance_destroy(admin_ctxt, instance_ref['id'])
1667
def test_filters_for_instance_with_ip_v6(self):
1668
self.flags(use_ipv6=True)
1669
network_info = _fake_network_info(self.stubs, 1)
1670
rulesv4, rulesv6 = self.fw._filters_for_instance("fake", network_info)
1671
self.assertEquals(len(rulesv4), 2)
1672
self.assertEquals(len(rulesv6), 1)
1674
def test_filters_for_instance_without_ip_v6(self):
1675
self.flags(use_ipv6=False)
1676
network_info = _fake_network_info(self.stubs, 1)
1677
rulesv4, rulesv6 = self.fw._filters_for_instance("fake", network_info)
1678
self.assertEquals(len(rulesv4), 2)
1679
self.assertEquals(len(rulesv6), 0)
1681
def test_multinic_iptables(self):
1682
ipv4_rules_per_addr = 1
1683
ipv4_addr_per_network = 2
1684
ipv6_rules_per_addr = 1
1685
ipv6_addr_per_network = 1
1687
instance_ref = self._create_instance_ref()
1688
network_info = _fake_network_info(self.stubs, networks_count,
1689
ipv4_addr_per_network)
1690
ipv4_len = len(self.fw.iptables.ipv4['filter'].rules)
1691
ipv6_len = len(self.fw.iptables.ipv6['filter'].rules)
1692
inst_ipv4, inst_ipv6 = self.fw.instance_rules(instance_ref,
1694
self.fw.prepare_instance_filter(instance_ref, network_info)
1695
ipv4 = self.fw.iptables.ipv4['filter'].rules
1696
ipv6 = self.fw.iptables.ipv6['filter'].rules
1697
ipv4_network_rules = len(ipv4) - len(inst_ipv4) - ipv4_len
1698
ipv6_network_rules = len(ipv6) - len(inst_ipv6) - ipv6_len
1699
self.assertEquals(ipv4_network_rules,
1700
ipv4_rules_per_addr * ipv4_addr_per_network * networks_count)
1701
self.assertEquals(ipv6_network_rules,
1702
ipv6_rules_per_addr * ipv6_addr_per_network * networks_count)
1704
def test_do_refresh_security_group_rules(self):
1705
instance_ref = self._create_instance_ref()
1706
self.mox.StubOutWithMock(self.fw,
1707
'add_filters_for_instance',
1708
use_mock_anything=True)
1709
self.fw.prepare_instance_filter(instance_ref, mox.IgnoreArg())
1710
self.fw.instances[instance_ref['id']] = instance_ref
1711
self.mox.ReplayAll()
1712
self.fw.do_refresh_security_group_rules("fake")
1714
@test.skip_if(missing_libvirt(), "Test requires libvirt")
1715
def test_unfilter_instance_undefines_nwfilter(self):
1716
admin_ctxt = context.get_admin_context()
1718
fakefilter = NWFilterFakes()
1719
_xml_mock = fakefilter.filterDefineXMLMock
1720
self.fw.nwfilter._conn.nwfilterDefineXML = _xml_mock
1721
_lookup_name = fakefilter.nwfilterLookupByName
1722
self.fw.nwfilter._conn.nwfilterLookupByName = _lookup_name
1723
instance_ref = self._create_instance_ref()
1725
network_info = _fake_network_info(self.stubs, 1)
1726
self.fw.setup_basic_filtering(instance_ref, network_info)
1727
self.fw.prepare_instance_filter(instance_ref, network_info)
1728
self.fw.apply_instance_filter(instance_ref, network_info)
1729
original_filter_count = len(fakefilter.filters)
1730
self.fw.unfilter_instance(instance_ref, network_info)
1732
# should undefine just the instance filter
1733
self.assertEqual(original_filter_count - len(fakefilter.filters), 1)
1735
db.instance_destroy(admin_ctxt, instance_ref['id'])
1737
def test_provider_firewall_rules(self):
1738
# setup basic instance data
1739
instance_ref = self._create_instance_ref()
1740
# FRAGILE: peeks at how the firewall names chains
1741
chain_name = 'inst-%s' % instance_ref['id']
1743
# create a firewall via setup_basic_filtering like libvirt_conn.spawn
1744
# should have a chain with 0 rules
1745
network_info = _fake_network_info(self.stubs, 1)
1746
self.fw.setup_basic_filtering(instance_ref, network_info)
1747
self.assertTrue('provider' in self.fw.iptables.ipv4['filter'].chains)
1748
rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
1749
if rule.chain == 'provider']
1750
self.assertEqual(0, len(rules))
1752
admin_ctxt = context.get_admin_context()
1753
# add a rule and send the update message, check for 1 rule
1754
provider_fw0 = db.provider_fw_rule_create(admin_ctxt,
1756
'cidr': '10.99.99.99/32',
1759
self.fw.refresh_provider_fw_rules()
1760
rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
1761
if rule.chain == 'provider']
1762
self.assertEqual(1, len(rules))
1764
# Add another, refresh, and make sure number of rules goes to two
1765
provider_fw1 = db.provider_fw_rule_create(admin_ctxt,
1767
'cidr': '10.99.99.99/32',
1770
self.fw.refresh_provider_fw_rules()
1771
rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
1772
if rule.chain == 'provider']
1773
self.assertEqual(2, len(rules))
1775
# create the instance filter and make sure it has a jump rule
1776
self.fw.prepare_instance_filter(instance_ref, network_info)
1777
self.fw.apply_instance_filter(instance_ref, network_info)
1778
inst_rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
1779
if rule.chain == chain_name]
1780
jump_rules = [rule for rule in inst_rules if '-j' in rule.rule]
1782
# IptablesTable doesn't make rules unique internally
1783
for rule in jump_rules:
1784
if 'provider' in rule.rule and rule not in provjump_rules:
1785
provjump_rules.append(rule)
1786
self.assertEqual(1, len(provjump_rules))
1788
# remove a rule from the db, cast to compute to refresh rule
1789
db.provider_fw_rule_destroy(admin_ctxt, provider_fw1['id'])
1790
self.fw.refresh_provider_fw_rules()
1791
rules = [rule for rule in self.fw.iptables.ipv4['filter'].rules
1792
if rule.chain == 'provider']
1793
self.assertEqual(1, len(rules))
1796
class NWFilterTestCase(test.TestCase):
1798
super(NWFilterTestCase, self).setUp()
1803
self.user_id = 'fake'
1804
self.project_id = 'fake'
1805
self.context = context.RequestContext(self.user_id, self.project_id)
1807
self.fake_libvirt_connection = Mock()
1809
self.fw = firewall.NWFilterFirewall(
1810
lambda: self.fake_libvirt_connection)
1812
def test_cidr_rule_nwfilter_xml(self):
1813
cloud_controller = cloud.CloudController()
1814
cloud_controller.create_security_group(self.context,
1816
'test group description')
1817
cloud_controller.authorize_security_group_ingress(self.context,
1822
cidr_ip='0.0.0.0/0')
1824
security_group = db.security_group_get_by_name(self.context,
1827
self.teardown_security_group()
1829
def teardown_security_group(self):
1830
cloud_controller = cloud.CloudController()
1831
cloud_controller.delete_security_group(self.context, 'testgroup')
1833
def setup_and_return_security_group(self):
1834
cloud_controller = cloud.CloudController()
1835
cloud_controller.create_security_group(self.context,
1837
'test group description')
1838
cloud_controller.authorize_security_group_ingress(self.context,
1843
cidr_ip='0.0.0.0/0')
1845
return db.security_group_get_by_name(self.context, 'fake', 'testgroup')
1847
def _create_instance(self):
1848
return db.instance_create(self.context,
1850
'project_id': 'fake',
1851
'instance_type_id': 1})
1853
def _create_instance_type(self, params=None):
1854
"""Create a test instance"""
1858
context = self.context.elevated()
1860
inst['name'] = 'm1.small'
1861
inst['memory_mb'] = '1024'
1863
inst['root_gb'] = '10'
1864
inst['ephemeral_gb'] = '20'
1865
inst['flavorid'] = '1'
1866
inst['swap'] = '2048'
1867
inst['rxtx_factor'] = 1
1869
return db.instance_type_create(context, inst)['id']
1871
def test_creates_base_rule_first(self):
1872
# These come pre-defined by libvirt
1873
self.defined_filters = ['no-mac-spoofing',
1876
'allow-dhcp-server']
1878
self.recursive_depends = {}
1879
for f in self.defined_filters:
1880
self.recursive_depends[f] = []
1882
def _filterDefineXMLMock(xml):
1883
dom = minidom.parseString(xml)
1884
name = dom.firstChild.getAttribute('name')
1885
self.recursive_depends[name] = []
1886
for f in dom.getElementsByTagName('filterref'):
1887
ref = f.getAttribute('filter')
1888
self.assertTrue(ref in self.defined_filters,
1889
('%s referenced filter that does ' +
1890
'not yet exist: %s') % (name, ref))
1891
dependencies = [ref] + self.recursive_depends[ref]
1892
self.recursive_depends[name] += dependencies
1894
self.defined_filters.append(name)
1897
self.fake_libvirt_connection.nwfilterDefineXML = _filterDefineXMLMock
1899
instance_ref = self._create_instance()
1900
inst_id = instance_ref['id']
1901
inst_uuid = instance_ref['uuid']
1903
def _ensure_all_called(mac):
1904
instance_filter = 'nova-instance-%s-%s' % (instance_ref['name'],
1905
mac.translate(None, ':'))
1906
for required in ['allow-dhcp-server',
1907
'no-arp-spoofing', 'no-ip-spoofing',
1909
self.assertTrue(required in
1910
self.recursive_depends[instance_filter],
1911
"Instance's filter does not include %s" %
1914
self.security_group = self.setup_and_return_security_group()
1916
db.instance_add_security_group(self.context, inst_uuid,
1917
self.security_group.id)
1918
instance = db.instance_get(self.context, inst_id)
1920
network_info = _fake_network_info(self.stubs, 1)
1921
# since there is one (network_info) there is one vif
1922
# pass this vif's mac to _ensure_all_called()
1923
# to set the instance_filter properly
1924
mac = network_info[0][1]['mac']
1926
self.fw.setup_basic_filtering(instance, network_info)
1927
_ensure_all_called(mac)
1928
db.instance_remove_security_group(self.context, inst_uuid,
1929
self.security_group.id)
1930
self.teardown_security_group()
1931
db.instance_destroy(context.get_admin_context(), instance_ref['id'])
1933
def test_unfilter_instance_undefines_nwfilters(self):
1934
admin_ctxt = context.get_admin_context()
1936
fakefilter = NWFilterFakes()
1937
self.fw._conn.nwfilterDefineXML = fakefilter.filterDefineXMLMock
1938
self.fw._conn.nwfilterLookupByName = fakefilter.nwfilterLookupByName
1940
instance_ref = self._create_instance()
1941
inst_id = instance_ref['id']
1942
inst_uuid = instance_ref['uuid']
1944
self.security_group = self.setup_and_return_security_group()
1946
db.instance_add_security_group(self.context, inst_uuid,
1947
self.security_group.id)
1949
instance = db.instance_get(self.context, inst_id)
1951
network_info = _fake_network_info(self.stubs, 1)
1952
self.fw.setup_basic_filtering(instance, network_info)
1953
original_filter_count = len(fakefilter.filters)
1954
self.fw.unfilter_instance(instance, network_info)
1955
self.assertEqual(original_filter_count - len(fakefilter.filters), 1)
1957
db.instance_destroy(admin_ctxt, instance_ref['id'])
1960
class LibvirtUtilsTestCase(test.TestCase):
1961
def test_get_iscsi_initiator(self):
1962
self.mox.StubOutWithMock(utils, 'execute')
1963
initiator = 'fake.initiator.iqn'
1964
rval = ("junk\nInitiatorName=%s\njunk\n" % initiator, None)
1965
utils.execute('cat', '/etc/iscsi/initiatorname.iscsi',
1966
run_as_root=True).AndReturn(rval)
1968
self.mox.ReplayAll()
1969
result = libvirt_utils.get_iscsi_initiator()
1970
self.assertEqual(initiator, result)
1972
def test_create_image(self):
1973
self.mox.StubOutWithMock(utils, 'execute')
1974
utils.execute('qemu-img', 'create', '-f', 'raw',
1975
'/some/path', '10G')
1976
utils.execute('qemu-img', 'create', '-f', 'qcow2',
1977
'/some/stuff', '1234567891234')
1979
self.mox.ReplayAll()
1980
libvirt_utils.create_image('raw', '/some/path', '10G')
1981
libvirt_utils.create_image('qcow2', '/some/stuff', '1234567891234')
1983
def test_create_cow_image(self):
1984
self.mox.StubOutWithMock(utils, 'execute')
1985
utils.execute('qemu-img', 'create', '-f', 'qcow2',
1986
'-o', 'cluster_size=2M,backing_file=/some/path',
1989
self.mox.ReplayAll()
1990
libvirt_utils.create_cow_image('/some/path', '/the/new/cow')
1992
def test_get_disk_size(self):
1993
self.mox.StubOutWithMock(utils, 'execute')
1994
utils.execute('qemu-img',
1996
'/some/path').AndReturn(('''image: 00000001
1998
virtual size: 4.4M (4592640 bytes)
1999
disk size: 4.4M''', ''))
2002
self.mox.ReplayAll()
2003
self.assertEquals(libvirt_utils.get_disk_size('/some/path'), 4592640)
2005
def test_copy_image(self):
2006
dst_fd, dst_path = tempfile.mkstemp()
2010
src_fd, src_path = tempfile.mkstemp()
2012
with os.fdopen(src_fd, 'w') as fp:
2015
libvirt_utils.copy_image(src_path, dst_path)
2016
with open(dst_path, 'r') as fp:
2017
self.assertEquals(fp.read(), 'canary')
2023
def test_mkfs(self):
2024
self.mox.StubOutWithMock(utils, 'execute')
2025
utils.execute('mkfs', '-t', 'ext4', '/my/block/dev')
2026
utils.execute('mkswap', '/my/swap/block/dev')
2027
self.mox.ReplayAll()
2029
libvirt_utils.mkfs('ext4', '/my/block/dev')
2030
libvirt_utils.mkfs('swap', '/my/swap/block/dev')
2032
def test_ensure_tree(self):
2033
with utils.tempdir() as tmpdir:
2034
testdir = '%s/foo/bar/baz' % (tmpdir,)
2035
libvirt_utils.ensure_tree(testdir)
2036
self.assertTrue(os.path.isdir(testdir))
2038
def test_write_to_file(self):
2039
dst_fd, dst_path = tempfile.mkstemp()
2043
libvirt_utils.write_to_file(dst_path, 'hello')
2044
with open(dst_path, 'r') as fp:
2045
self.assertEquals(fp.read(), 'hello')
2049
def test_write_to_file_with_umask(self):
2050
dst_fd, dst_path = tempfile.mkstemp()
2055
libvirt_utils.write_to_file(dst_path, 'hello', umask=0277)
2056
with open(dst_path, 'r') as fp:
2057
self.assertEquals(fp.read(), 'hello')
2058
mode = os.stat(dst_path).st_mode
2059
self.assertEquals(mode & 0277, 0)
2063
def test_chown(self):
2064
self.mox.StubOutWithMock(utils, 'execute')
2065
utils.execute('chown', 'soren', '/some/path', run_as_root=True)
2066
self.mox.ReplayAll()
2067
libvirt_utils.chown('/some/path', 'soren')
2069
def test_extract_snapshot(self):
2070
self.mox.StubOutWithMock(utils, 'execute')
2071
utils.execute('qemu-img', 'convert', '-f', 'qcow2', '-O', 'raw',
2072
'-s', 'snap1', '/path/to/disk/image', '/extracted/snap')
2075
self.mox.ReplayAll()
2076
libvirt_utils.extract_snapshot('/path/to/disk/image', 'qcow2',
2077
'snap1', '/extracted/snap', 'raw')
2079
def test_load_file(self):
2080
dst_fd, dst_path = tempfile.mkstemp()
2084
# We have a test for write_to_file. If that is sound, this suffices
2085
libvirt_utils.write_to_file(dst_path, 'hello')
2086
self.assertEquals(libvirt_utils.load_file(dst_path), 'hello')
2090
def test_file_open(self):
2091
dst_fd, dst_path = tempfile.mkstemp()
2095
# We have a test for write_to_file. If that is sound, this suffices
2096
libvirt_utils.write_to_file(dst_path, 'hello')
2097
with libvirt_utils.file_open(dst_path, 'r') as fp:
2098
self.assertEquals(fp.read(), 'hello')
2102
def test_get_fs_info(self):
2104
class FakeStatResult(object):
2108
self.f_frsize = 4096
2109
self.f_blocks = 2000
2116
self.f_namemax = 255
2120
def fake_statvfs(path):
2122
return FakeStatResult()
2124
self.stubs.Set(os, 'statvfs', fake_statvfs)
2126
fs_info = libvirt_utils.get_fs_info('/some/file/path')
2127
self.assertEquals('/some/file/path', self.path)
2128
self.assertEquals(8192000, fs_info['total'])
2129
self.assertEquals(3686400, fs_info['free'])
2130
self.assertEquals(4096000, fs_info['used'])
2132
def test_fetch_image(self):
2133
self.mox.StubOutWithMock(images, 'fetch_to_raw')
2135
context = 'opaque context'
2136
target = '/tmp/targetfile'
2140
images.fetch_to_raw(context, image_id, target, user_id, project_id)
2142
self.mox.ReplayAll()
2143
libvirt_utils.fetch_image(context, target, image_id,
2144
user_id, project_id)
2147
class LibvirtConnectionTestCase(test.TestCase):
2148
"""Test for nova.virt.libvirt.connection.LibvirtConnection."""
2150
super(LibvirtConnectionTestCase, self).setUp()
2151
self.libvirtconnection = connection.LibvirtConnection(read_only=True)
2153
def _create_instance(self, params=None):
2154
"""Create a test instance"""
2159
inst['image_ref'] = '1'
2160
inst['reservation_id'] = 'r-fakeres'
2161
inst['launch_time'] = '10'
2162
inst['user_id'] = 'fake'
2163
inst['project_id'] = 'fake'
2164
type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
2165
inst['instance_type_id'] = type_id
2166
inst['ami_launch_index'] = 0
2167
inst['host'] = 'host1'
2168
inst['root_gb'] = 10
2169
inst['ephemeral_gb'] = 20
2170
inst['config_drive'] = 1
2171
inst['kernel_id'] = 2
2172
inst['ramdisk_id'] = 3
2173
inst['config_drive_id'] = 1
2174
inst['key_data'] = 'ABCDEFG'
2177
return db.instance_create(context.get_admin_context(), inst)
2179
def test_migrate_disk_and_power_off_exception(self):
2180
"""Test for nova.virt.libvirt.connection.LivirtConnection
2181
.migrate_disk_and_power_off. """
2185
def fake_get_instance_disk_info(instance):
2188
def fake_destroy(instance, network_info, cleanup=True):
2191
def fake_get_host_ip_addr():
2194
def fake_execute(*args, **kwargs):
2196
if self.counter == 1:
2197
assert False, "intentional failure"
2199
def fake_os_path_exists(path):
2202
self.stubs.Set(self.libvirtconnection, 'get_instance_disk_info',
2203
fake_get_instance_disk_info)
2204
self.stubs.Set(self.libvirtconnection, '_destroy', fake_destroy)
2205
self.stubs.Set(self.libvirtconnection, 'get_host_ip_addr',
2206
fake_get_host_ip_addr)
2207
self.stubs.Set(utils, 'execute', fake_execute)
2208
self.stubs.Set(os.path, 'exists', fake_os_path_exists)
2210
ins_ref = self._create_instance()
2212
self.assertRaises(AssertionError,
2213
self.libvirtconnection.migrate_disk_and_power_off,
2214
None, ins_ref, '10.0.0.2', None, None)
2216
def test_migrate_disk_and_power_off(self):
2217
"""Test for nova.virt.libvirt.connection.LivirtConnection
2218
.migrate_disk_and_power_off. """
2220
disk_info = [{'type': 'qcow2', 'path': '/test/disk',
2221
'virt_disk_size': '10737418240',
2222
'backing_file': '/base/disk',
2223
'disk_size':'83886080'},
2224
{'type': 'raw', 'path': '/test/disk.local',
2225
'virt_disk_size': '10737418240',
2226
'backing_file': '/base/disk.local',
2227
'disk_size':'83886080'}]
2228
disk_info_text = utils.dumps(disk_info)
2230
def fake_get_instance_disk_info(instance):
2231
return disk_info_text
2233
def fake_destroy(instance, network_info, cleanup=True):
2236
def fake_get_host_ip_addr():
2239
def fake_execute(*args, **kwargs):
2242
self.stubs.Set(self.libvirtconnection, 'get_instance_disk_info',
2243
fake_get_instance_disk_info)
2244
self.stubs.Set(self.libvirtconnection, '_destroy', fake_destroy)
2245
self.stubs.Set(self.libvirtconnection, 'get_host_ip_addr',
2246
fake_get_host_ip_addr)
2247
self.stubs.Set(utils, 'execute', fake_execute)
2249
ins_ref = self._create_instance()
2250
""" dest is different host case """
2251
out = self.libvirtconnection.migrate_disk_and_power_off(
2252
None, ins_ref, '10.0.0.2', None, None)
2253
self.assertEquals(out, disk_info_text)
2255
""" dest is same host case """
2256
out = self.libvirtconnection.migrate_disk_and_power_off(
2257
None, ins_ref, '10.0.0.1', None, None)
2258
self.assertEquals(out, disk_info_text)
2260
def test_wait_for_running(self):
2261
"""Test for nova.virt.libvirt.connection.LivirtConnection
2262
._wait_for_running. """
2264
def fake_get_info(instance):
2265
if instance['name'] == "not_found":
2266
raise exception.NotFound
2267
elif instance['name'] == "running":
2268
return {'state': power_state.RUNNING}
2270
return {'state': power_state.SHUTOFF}
2272
self.stubs.Set(self.libvirtconnection, 'get_info',
2275
""" instance not found case """
2276
self.assertRaises(utils.LoopingCallDone,
2277
self.libvirtconnection._wait_for_running,
2278
{'name': 'not_found',
2279
'uuid': 'not_found_uuid'})
2281
""" instance is running case """
2282
self.assertRaises(utils.LoopingCallDone,
2283
self.libvirtconnection._wait_for_running,
2285
'uuid': 'running_uuid'})
2288
self.libvirtconnection._wait_for_running({'name': 'else',
2289
'uuid': 'other_uuid'})
2291
def test_finish_migration(self):
2292
"""Test for nova.virt.libvirt.connection.LivirtConnection
2293
.finish_migration. """
2295
disk_info = [{'type': 'qcow2', 'path': '/test/disk',
2296
'local_gb': 10, 'backing_file': '/base/disk'},
2297
{'type': 'raw', 'path': '/test/disk.local',
2298
'local_gb': 10, 'backing_file': '/base/disk.local'}]
2299
disk_info_text = utils.dumps(disk_info)
2301
def fake_extend(path, size):
2304
def fake_to_xml(instance, network_info):
2307
def fake_plug_vifs(instance, network_info):
2310
def fake_create_image(context, inst, libvirt_xml, suffix='',
2311
disk_images=None, network_info=None,
2312
block_device_info=None):
2315
def fake_create_new_domain(xml):
2318
def fake_execute(*args, **kwargs):
2321
self.flags(use_cow_images=True)
2322
self.stubs.Set(connection.disk, 'extend', fake_extend)
2323
self.stubs.Set(self.libvirtconnection, 'to_xml', fake_to_xml)
2324
self.stubs.Set(self.libvirtconnection, 'plug_vifs', fake_plug_vifs)
2325
self.stubs.Set(self.libvirtconnection, '_create_image',
2327
self.stubs.Set(self.libvirtconnection, '_create_new_domain',
2328
fake_create_new_domain)
2329
self.stubs.Set(utils, 'execute', fake_execute)
2330
fw = base_firewall.NoopFirewallDriver()
2331
self.stubs.Set(self.libvirtconnection, 'firewall_driver', fw)
2333
ins_ref = self._create_instance()
2335
ref = self.libvirtconnection.finish_migration(
2336
context.get_admin_context(), None, ins_ref,
2337
disk_info_text, None, None, None)
2338
self.assertTrue(isinstance(ref, eventlet.event.Event))
2340
def test_finish_revert_migration(self):
2341
"""Test for nova.virt.libvirt.connection.LivirtConnection
2342
.finish_revert_migration. """
2344
def fake_execute(*args, **kwargs):
2347
def fake_plug_vifs(instance, network_info):
2350
def fake_create_new_domain(xml):
2353
self.stubs.Set(self.libvirtconnection, 'plug_vifs', fake_plug_vifs)
2354
self.stubs.Set(utils, 'execute', fake_execute)
2355
fw = base_firewall.NoopFirewallDriver()
2356
self.stubs.Set(self.libvirtconnection, 'firewall_driver', fw)
2357
self.stubs.Set(self.libvirtconnection, '_create_new_domain',
2358
fake_create_new_domain)
2360
with utils.tempdir() as tmpdir:
2361
self.flags(instances_path=tmpdir)
2362
ins_ref = self._create_instance()
2363
os.mkdir(os.path.join(tmpdir, ins_ref['name']))
2364
libvirt_xml_path = os.path.join(tmpdir,
2367
f = open(libvirt_xml_path, 'w')
2370
ref = self.libvirtconnection.finish_revert_migration(ins_ref, None)
2371
self.assertTrue(isinstance(ref, eventlet.event.Event))