summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2011-09-30 15:40:04 +0000
committerGerrit Code Review <review@openstack.org>2011-09-30 15:40:04 +0000
commit96b99e4d1f5f264e7f263ddbf50981abf5a3b04e (patch)
treea20a6d10fce59da6232e30eedb8f5555aeb28383
parentcb6250fa77d7724ba7e5dd15e8a3c9973756c1f5 (diff)
parentb9aac1181581b9036c98f5aa493731fdc74be7e1 (diff)
downloadnova-96b99e4d1f5f264e7f263ddbf50981abf5a3b04e.tar.gz
nova-96b99e4d1f5f264e7f263ddbf50981abf5a3b04e.tar.xz
nova-96b99e4d1f5f264e7f263ddbf50981abf5a3b04e.zip
Merge "Fixed bug lp850602. Adding backing file copy operation on kvm block migration."
-rw-r--r--nova/tests/test_libvirt.py26
-rw-r--r--nova/virt/libvirt/connection.py33
2 files changed, 47 insertions, 12 deletions
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index aefe26cc8..8b6f2080d 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -629,9 +629,12 @@ class LibvirtConnTestCase(test.TestCase):
fake_timer = FakeTime()
+ # _fake_network_info must be called before create_fake_libvirt_mock(),
+ # as _fake_network_info calls utils.import_class() and
+ # create_fake_libvirt_mock() mocks utils.import_class().
+ network_info = _fake_network_info(self.stubs, 1)
self.create_fake_libvirt_mock()
instance_ref = db.instance_create(self.context, self.test_instance)
- network_info = _fake_network_info(self.stubs, 1)
# Start test
self.mox.ReplayAll()
@@ -684,10 +687,7 @@ class LibvirtConnTestCase(test.TestCase):
return vdmock
self.create_fake_libvirt_mock(lookupByName=fake_lookup)
-# self.mox.StubOutWithMock(self.compute, "recover_live_migration")
self.mox.StubOutWithMock(self.compute, "rollback_live_migration")
-# self.compute.recover_live_migration(self.context, instance_ref,
-# dest='dest')
self.compute.rollback_live_migration(self.context, instance_ref,
'dest', False)
@@ -722,7 +722,8 @@ class LibvirtConnTestCase(test.TestCase):
# Test data
instance_ref = db.instance_create(self.context, self.test_instance)
- dummyjson = '[{"path": "%s/disk", "local_gb": "10G", "type": "raw"}]'
+ dummyjson = ('[{"path": "%s/disk", "local_gb": "10G",'
+ ' "type": "raw", "backing_file": ""}]')
# Preparing mocks
# qemu-img should be mockd since test environment might not have
@@ -763,7 +764,10 @@ class LibvirtConnTestCase(test.TestCase):
"</devices></domain>")
ret = ("image: /test/disk\nfile format: raw\n"
- "virtual size: 20G (21474836480 bytes)\ndisk size: 3.1G\n")
+ "virtual size: 20G (21474836480 bytes)\ndisk size: 3.1G\n"
+ "disk size: 102M\n"
+ "cluster_size: 2097152\n"
+ "backing file: /test/dummy (actual path: /backing/file)\n")
# Preparing mocks
vdmock = self.mox.CreateMock(libvirt.virDomain)
@@ -793,7 +797,9 @@ class LibvirtConnTestCase(test.TestCase):
info[0]['path'] == '/test/disk' and
info[1]['path'] == '/test/disk.local' and
info[0]['local_gb'] == '10G' and
- info[1]['local_gb'] == '20G')
+ info[1]['local_gb'] == '20G' and
+ info[0]['backing_file'] == "" and
+ info[1]['backing_file'] == "file")
db.instance_destroy(self.context, instance_ref['id'])
@@ -806,6 +812,10 @@ class LibvirtConnTestCase(test.TestCase):
def fake_none(self, instance):
return
+ # _fake_network_info must be called before create_fake_libvirt_mock(),
+ # as _fake_network_info calls utils.import_class() and
+ # create_fake_libvirt_mock() mocks utils.import_class().
+ network_info = _fake_network_info(self.stubs, 1)
self.create_fake_libvirt_mock()
instance = db.instance_create(self.context, self.test_instance)
@@ -815,8 +825,6 @@ class LibvirtConnTestCase(test.TestCase):
conn.firewall_driver.setattr('setup_basic_filtering', fake_none)
conn.firewall_driver.setattr('prepare_instance_filter', fake_none)
- network_info = _fake_network_info(self.stubs, 1)
-
try:
conn.spawn(self.context, instance, network_info)
except Exception, e:
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index 6afd41c1b..03b1a4ba4 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -1728,9 +1728,31 @@ class LibvirtConnection(driver.ComputeDriver):
for info in disk_info:
base = os.path.basename(info['path'])
- # Get image type and create empty disk image.
+ # Get image type and create empty disk image, and
+ # create backing file in case of qcow2.
instance_disk = os.path.join(instance_dir, base)
- utils.execute('qemu-img', 'create', '-f', info['type'],
+ if not info['backing_file']:
+ utils.execute('qemu-img', 'create', '-f', info['type'],
+ instance_disk, info['local_gb'])
+
+ else:
+ # Creating backing file follows same way as spawning instances.
+ backing_file = os.path.join(FLAGS.instances_path,
+ '_base', info['backing_file'])
+
+ if not os.path.exists(backing_file):
+ self._cache_image(fn=self._fetch_image,
+ context=ctxt,
+ target=info['path'],
+ fname=info['backing_file'],
+ cow=FLAGS.use_cow_images,
+ image_id=instance_ref['image_ref'],
+ user_id=instance_ref['user_id'],
+ project_id=instance_ref['project_id'],
+ size=instance_ref['local_gb'])
+
+ utils.execute('qemu-img', 'create', '-f', info['type'],
+ '-o', 'backing_file=%s' % backing_file,
instance_disk, info['local_gb'])
# if image has kernel and ramdisk, just download
@@ -1821,12 +1843,17 @@ class LibvirtConnection(driver.ComputeDriver):
driver_nodes[cnt].get_properties().get_next().getContent()
if disk_type == 'raw':
size = int(os.path.getsize(path))
+ backing_file = ""
else:
out, err = utils.execute('qemu-img', 'info', path)
size = [i.split('(')[1].split()[0] for i in out.split('\n')
if i.strip().find('virtual size') >= 0]
size = int(size[0])
+ backing_file = [i.split('actual path:')[1].strip()[:-1]
+ for i in out.split('\n') if 0 <= i.find('backing file')]
+ backing_file = os.path.basename(backing_file[0])
+
# block migration needs same/larger size of empty image on the
# destination host. since qemu-img creates bit smaller size image
# depending on original image size, fixed value is necessary.
@@ -1842,7 +1869,7 @@ class LibvirtConnection(driver.ComputeDriver):
break
disk_info.append({'type': disk_type, 'path': path,
- 'local_gb': size})
+ 'local_gb': size, 'backing_file': backing_file})
return utils.dumps(disk_info)