virt: convert disk API over to use nova.virt.image.model

Convert the nova.virt.disk.api methods over to use the
nova.virt.image.model classes instead of taking a file
path and use_cow boolean as parameters.

Related-Bug: #1257674
Change-Id: I34e2f29e1f068636036226a7745d88640f724d93
This commit is contained in:
Daniel P. Berrange 2014-10-29 19:57:20 +00:00
parent d81f6eb4d3
commit 5453d4b7a1
7 changed files with 177 additions and 125 deletions

View File

@ -78,8 +78,9 @@ class APITestCase(test.NoDBTestCase):
fake_import_fails))
imgfile = tempfile.NamedTemporaryFile()
image = imgmodel.LocalFileImage(imgfile, imgmodel.FORMAT_QCOW2)
self.addCleanup(imgfile.close)
self.assertFalse(api.is_image_extendable(imgfile, use_cow=True))
self.assertFalse(api.is_image_extendable(image))
def test_resize2fs_success(self):
imgfile = tempfile.NamedTemporaryFile()
@ -115,7 +116,6 @@ class APITestCase(test.NoDBTestCase):
imgfile = tempfile.NamedTemporaryFile()
imgsize = 10
device = "/dev/sdh"
use_cow = True
image = imgmodel.LocalFileImage(imgfile, imgmodel.FORMAT_QCOW2)
self.flags(resize_fs_using_block_device=True)
@ -134,14 +134,14 @@ class APITestCase(test.NoDBTestCase):
api.can_resize_image(imgfile, imgsize).AndReturn(True)
utils.execute('qemu-img', 'resize', imgfile, imgsize)
api.is_image_extendable(imgfile, use_cow).AndReturn(True)
api.is_image_extendable(image).AndReturn(True)
mount.Mount.instance_for_format(image, None, None).AndReturn(mounter)
mounter.get_dev().AndReturn(True)
api.resize2fs(mounter.device, run_as_root=True, check_exit_code=[0])
mounter.unget_dev()
self.mox.ReplayAll()
api.extend(imgfile, imgsize, use_cow=use_cow)
api.extend(image, imgsize)
@mock.patch.object(api, 'can_resize_image', return_value=True)
@mock.patch.object(api, 'is_image_extendable')
@ -150,10 +150,11 @@ class APITestCase(test.NoDBTestCase):
mock_can_resize_image):
imgfile = tempfile.NamedTemporaryFile()
imgsize = 10
image = imgmodel.LocalFileImage(imgfile, imgmodel.FORMAT_QCOW2)
self.flags(resize_fs_using_block_device=False)
api.extend(imgfile, imgsize, use_cow=True)
api.extend(image, imgsize)
mock_can_resize_image.assert_called_once_with(imgfile, imgsize)
mock_execute.assert_called_once_with('qemu-img', 'resize', imgfile,
@ -163,7 +164,7 @@ class APITestCase(test.NoDBTestCase):
def test_extend_raw_success(self):
imgfile = tempfile.NamedTemporaryFile()
imgsize = 10
use_cow = False
image = imgmodel.LocalFileImage(imgfile, imgmodel.FORMAT_RAW)
self.mox.StubOutWithMock(api, 'can_resize_image')
self.mox.StubOutWithMock(utils, 'execute')
@ -172,11 +173,11 @@ class APITestCase(test.NoDBTestCase):
api.can_resize_image(imgfile, imgsize).AndReturn(True)
utils.execute('qemu-img', 'resize', imgfile, imgsize)
api.is_image_extendable(imgfile, use_cow).AndReturn(True)
api.is_image_extendable(image).AndReturn(True)
api.resize2fs(imgfile, run_as_root=False, check_exit_code=[0])
self.mox.ReplayAll()
api.extend(imgfile, imgsize, use_cow=use_cow)
api.extend(image, imgsize)
HASH_VFAT = utils.get_hash_str(api.FS_FORMAT_VFAT)[:7]
HASH_EXT4 = utils.get_hash_str(api.FS_FORMAT_EXT4)[:7]

View File

@ -35,25 +35,34 @@ class VirtDiskTest(test.NoDBTestCase):
imgmodel.FORMAT_QCOW2)
def test_inject_data(self):
self.assertTrue(diskapi.inject_data("/some/file", use_cow=True))
self.assertTrue(diskapi.inject_data(
imgmodel.LocalFileImage("/some/file", imgmodel.FORMAT_QCOW2)))
self.assertTrue(diskapi.inject_data("/some/file",
mandatory=('files',)))
self.assertTrue(diskapi.inject_data(
imgmodel.LocalFileImage("/some/file", imgmodel.FORMAT_RAW),
mandatory=('files',)))
self.assertTrue(diskapi.inject_data("/some/file", key="mysshkey",
mandatory=('key',)))
self.assertTrue(diskapi.inject_data(
imgmodel.LocalFileImage("/some/file", imgmodel.FORMAT_RAW),
key="mysshkey",
mandatory=('key',)))
os_name = os.name
os.name = 'nt' # Cause password injection to fail
self.assertRaises(exception.NovaException,
diskapi.inject_data,
"/some/file", admin_password="p",
imgmodel.LocalFileImage("/some/file",
imgmodel.FORMAT_RAW),
admin_password="p",
mandatory=('admin_password',))
self.assertFalse(diskapi.inject_data("/some/file", admin_password="p"))
self.assertFalse(diskapi.inject_data(
imgmodel.LocalFileImage("/some/file", imgmodel.FORMAT_RAW),
admin_password="p"))
os.name = os_name
self.assertFalse(diskapi.inject_data("/some/fail/file",
key="mysshkey"))
self.assertFalse(diskapi.inject_data(
imgmodel.LocalFileImage("/some/fail/file", imgmodel.FORMAT_RAW),
key="mysshkey"))
def test_inject_data_key(self):

View File

@ -81,6 +81,7 @@ from nova.virt import driver
from nova.virt import fake
from nova.virt import firewall as base_firewall
from nova.virt import hardware
from nova.virt.image import model as imgmodel
from nova.virt.libvirt import blockinfo
from nova.virt.libvirt import config as vconfig
from nova.virt.libvirt import driver as libvirt_driver
@ -7168,9 +7169,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.flags(virt_type="lxc",
group='libvirt')
def check_setup_container(path, container_dir=None, use_cow=False):
self.assertEqual(path, '/dev/path/to/dev')
self.assertTrue(use_cow)
def check_setup_container(image, container_dir=None):
self.assertEqual(image.path, '/dev/path/to/dev')
self.assertEqual(image.format, imgmodel.FORMAT_QCOW2)
return '/dev/nbd1'
bdm = {
@ -9978,9 +9979,14 @@ class LibvirtConnTestCase(test.NoDBTestCase):
mock_ensure_tree.assert_has_calls([mock.call('/tmp/rootfs')])
drvr.image_backend.image.assert_has_calls([mock.call(mock_instance,
'disk')])
setup_container_call = mock.call('/tmp/test.img',
container_dir='/tmp/rootfs',
use_cow=CONF.use_cow_images)
fmt = imgmodel.FORMAT_RAW
if CONF.use_cow_images:
fmt = imgmodel.FORMAT_QCOW2
setup_container_call = mock.call(
imgmodel.LocalFileImage('/tmp/test.img', fmt),
container_dir='/tmp/rootfs')
mock_setup_container.assert_has_calls([setup_container_call])
mock_get_info.assert_has_calls([mock.call(mock_instance)])
mock_clean.assert_has_calls([mock.call(container_dir='/tmp/rootfs')])
@ -10041,9 +10047,14 @@ class LibvirtConnTestCase(test.NoDBTestCase):
mock_ensure_tree.assert_has_calls([mock.call('/tmp/rootfs')])
drvr.image_backend.image.assert_has_calls([mock.call(mock_instance,
'disk')])
setup_container_call = mock.call('/tmp/test.img',
container_dir='/tmp/rootfs',
use_cow=CONF.use_cow_images)
fmt = imgmodel.FORMAT_RAW
if CONF.use_cow_images:
fmt = imgmodel.FORMAT_QCOW2
setup_container_call = mock.call(
imgmodel.LocalFileImage('/tmp/test.img', fmt),
container_dir='/tmp/rootfs')
mock_setup_container.assert_has_calls([setup_container_call])
mock_get_info.assert_has_calls([mock.call(mock_instance)])
mock_clean.assert_has_calls([mock.call(container_dir='/tmp/rootfs')])
@ -10090,9 +10101,14 @@ class LibvirtConnTestCase(test.NoDBTestCase):
mock_ensure_tree.assert_has_calls([mock.call('/tmp/rootfs')])
drvr.image_backend.image.assert_has_calls([mock.call(mock_instance,
'disk')])
setup_container_call = mock.call('/tmp/test.img',
container_dir='/tmp/rootfs',
use_cow=CONF.use_cow_images)
fmt = imgmodel.FORMAT_RAW
if CONF.use_cow_images:
fmt = imgmodel.FORMAT_QCOW2
setup_container_call = mock.call(
imgmodel.LocalFileImage('/tmp/test.img', fmt),
container_dir='/tmp/rootfs')
mock_setup_container.assert_has_calls([setup_container_call])
mock_get_info.assert_has_calls([mock.call(mock_instance)])
teardown_call = mock.call(container_dir='/tmp/rootfs')
@ -11688,17 +11704,17 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
@mock.patch('nova.virt.disk.api.extend')
def test_disk_resize_raw(self, mock_extend):
info = {'type': 'raw', 'path': '/test/disk'}
image = imgmodel.LocalFileImage("/test/disk",
imgmodel.FORMAT_RAW)
self.drvr._disk_resize(info, 50)
mock_extend.assert_called_once_with(info['path'], 50, use_cow=False)
self.drvr._disk_resize(image, 50)
mock_extend.assert_called_once_with(image, 50)
@mock.patch('nova.virt.disk.api.can_resize_image')
@mock.patch('nova.virt.disk.api.is_image_extendable')
@mock.patch('nova.virt.disk.api.extend')
def test_disk_resize_qcow2(
self, mock_extend, mock_can_resize, mock_is_image_extendable):
info = {'type': 'qcow2', 'path': '/test/disk'}
with contextlib.nested(
mock.patch.object(
@ -11710,12 +11726,15 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
mock_can_resize.return_value = True
mock_is_image_extendable.return_value = True
self.drvr._disk_resize(info, 50)
imageqcow2 = imgmodel.LocalFileImage("/test/disk",
imgmodel.FORMAT_QCOW2)
imageraw = imgmodel.LocalFileImage("/test/disk",
imgmodel.FORMAT_RAW)
self.drvr._disk_resize(imageqcow2, 50)
mock_disk_qcow2_to_raw.assert_called_once_with(info['path'])
mock_extend.assert_called_once_with(
info['path'], 50, use_cow=False)
mock_disk_raw_to_qcow2.assert_called_once_with(info['path'])
mock_disk_qcow2_to_raw.assert_called_once_with(imageqcow2.path)
mock_extend.assert_called_once_with(imageraw, 50)
mock_disk_raw_to_qcow2.assert_called_once_with(imageqcow2.path)
def _test_finish_migration(self, power_on, resize_instance=False):
"""Test for nova.virt.libvirt.libvirt_driver.LivirtConnection
@ -11761,7 +11780,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
else:
return hardware.InstanceInfo(state=power_state.SHUTDOWN)
def fake_disk_resize(info, size):
def fake_disk_resize(image, size):
self.fake_disk_resize_called = True
self.flags(use_cow_images=True)
@ -12065,7 +12084,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
@mock.patch('nova.virt.netutils.get_injected_network_template')
@mock.patch('nova.virt.disk.api.inject_data')
def _test_inject_data(self, driver_params, disk_params,
def _test_inject_data(self, driver_params, path, disk_params,
disk_inject_data, inj_network,
called=True):
class ImageBackend(object):
@ -12081,7 +12100,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
inj_network.side_effect = fake_inj_network
image_backend = ImageBackend()
image_backend.path = disk_params[0]
image_backend.path = path
with mock.patch.object(
self.drvr.image_backend,
@ -12093,8 +12112,9 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
if called:
disk_inject_data.assert_called_once_with(
mock.ANY,
*disk_params,
partition=None, mandatory=('files',), use_cow=True)
partition=None, mandatory=('files',))
self.assertEqual(disk_inject_data.called, called)
@ -12112,18 +12132,18 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
driver_params = self._test_inject_data_default_driver_params()
driver_params['admin_pass'] = 'foobar'
disk_params = [
'/path', # injection_path
None, # key
None, # net
{}, # metadata
'foobar', # admin_pass
None, # files
]
self._test_inject_data(driver_params, disk_params)
self._test_inject_data(driver_params, "/path", disk_params)
# Test with the configuration setted to false.
self.flags(inject_password=False, group='libvirt')
self._test_inject_data(driver_params, disk_params, called=False)
self._test_inject_data(driver_params, "/path",
disk_params, called=False)
def test_inject_data_key(self):
driver_params = self._test_inject_data_default_driver_params()
@ -12131,18 +12151,18 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
self.flags(inject_key=True, group='libvirt')
disk_params = [
'/path', # injection_path
'key-content', # key
None, # net
{}, # metadata
None, # admin_pass
None, # files
]
self._test_inject_data(driver_params, disk_params)
self._test_inject_data(driver_params, "/path", disk_params)
# Test with the configuration setted to false.
self.flags(inject_key=False, group='libvirt')
self._test_inject_data(driver_params, disk_params, called=False)
self._test_inject_data(driver_params, "/path",
disk_params, called=False)
def test_inject_data_metadata(self):
instance_metadata = {'metadata': {'data': 'foo'}}
@ -12150,52 +12170,49 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
**instance_metadata
)
disk_params = [
'/path', # injection_path
None, # key
None, # net
{'data': 'foo'}, # metadata
None, # admin_pass
None, # files
]
self._test_inject_data(driver_params, disk_params)
self._test_inject_data(driver_params, "/path", disk_params)
def test_inject_data_files(self):
driver_params = self._test_inject_data_default_driver_params()
driver_params['files'] = ['file1', 'file2']
disk_params = [
'/path', # injection_path
None, # key
None, # net
{}, # metadata
None, # admin_pass
['file1', 'file2'], # files
]
self._test_inject_data(driver_params, disk_params)
self._test_inject_data(driver_params, "/path", disk_params)
def test_inject_data_net(self):
driver_params = self._test_inject_data_default_driver_params()
driver_params['network_info'] = {'net': 'eno1'}
disk_params = [
'/path', # injection_path
None, # key
{'net': 'eno1'}, # net
{}, # metadata
None, # admin_pass
None, # files
]
self._test_inject_data(driver_params, disk_params)
self._test_inject_data(driver_params, "/path", disk_params)
def test_inject_not_exist_image(self):
driver_params = self._test_inject_data_default_driver_params()
disk_params = [
'/fail/path', # injection_path
'key-content', # key
None, # net
None, # metadata
None, # admin_pass
None, # files
]
self._test_inject_data(driver_params, disk_params, called=False)
self._test_inject_data(driver_params, "/fail/path",
disk_params, called=False)
def _test_attach_detach_interface(self, method, power_state,
expected_flags):

View File

@ -35,6 +35,7 @@ from nova.openstack.common import imageutils
from nova import test
from nova.tests.unit import fake_processutils
from nova.tests.unit.virt.libvirt import fake_libvirt_utils
from nova.virt.image import model as imgmodel
from nova.virt import images
from nova.virt.libvirt import config as vconfig
from nova.virt.libvirt import imagebackend
@ -258,7 +259,8 @@ class RawTestCase(_ImageTestCase, test.NoDBTestCase):
fn = self.prepare_mocks()
fn(max_size=self.SIZE, target=self.TEMPLATE_PATH, image_id=None)
imagebackend.libvirt_utils.copy_image(self.TEMPLATE_PATH, self.PATH)
imagebackend.disk.extend(self.PATH, self.SIZE, use_cow=False)
image = imgmodel.LocalFileImage(self.PATH, imgmodel.FORMAT_RAW)
imagebackend.disk.extend(image, self.SIZE)
self.mox.ReplayAll()
image = self.image_class(self.INSTANCE, self.NAME)
@ -413,7 +415,8 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
imagebackend.Image.verify_base_size(self.TEMPLATE_PATH, self.SIZE)
imagebackend.libvirt_utils.create_cow_image(self.TEMPLATE_PATH,
self.PATH)
imagebackend.disk.extend(self.PATH, self.SIZE, use_cow=True)
image = imgmodel.LocalFileImage(self.PATH, imgmodel.FORMAT_QCOW2)
imagebackend.disk.extend(image, self.SIZE)
self.mox.ReplayAll()
image = self.image_class(self.INSTANCE, self.NAME)
@ -460,7 +463,9 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
imagebackend.Image.verify_base_size(self.TEMPLATE_PATH, self.SIZE)
imagebackend.libvirt_utils.copy_image(self.TEMPLATE_PATH,
self.QCOW2_BASE)
imagebackend.disk.extend(self.QCOW2_BASE, self.SIZE, use_cow=True)
image = imgmodel.LocalFileImage(self.QCOW2_BASE,
imgmodel.FORMAT_QCOW2)
imagebackend.disk.extend(image, self.SIZE)
os.path.exists(self.PATH).AndReturn(True)
self.mox.ReplayAll()

View File

@ -173,23 +173,28 @@ def get_disk_size(path):
return images.qemu_img_info(path).virtual_size
def extend(image, size, use_cow=False):
def extend(image, size):
"""Increase image to size.
:param image: path to disk image file
:param image: instance of nova.virt.image.model.Image
:param size: image size in bytes
:param use_cow: whether the disk is a qcow2 file
"""
if not can_resize_image(image, size):
# Currently can only resize FS in local images
if not isinstance(image, imgmodel.LocalImage):
return
utils.execute('qemu-img', 'resize', image, size)
if not can_resize_image(image.path, size):
return
if use_cow and not CONF.resize_fs_using_block_device:
utils.execute('qemu-img', 'resize', image.path, size)
if (image.format != imgmodel.FORMAT_RAW and
not CONF.resize_fs_using_block_device):
return
# if we can't access the filesystem, we can't do anything more
if not is_image_extendable(image, use_cow):
if not is_image_extendable(image):
return
def safe_resize2fs(dev, run_as_root=False, finally_call=lambda: None):
@ -202,23 +207,24 @@ def extend(image, size, use_cow=False):
finally_call()
# NOTE(vish): attempts to resize filesystem
if use_cow:
if image.format != imgmodel.FORMAT_RAW:
# in case of non-raw disks we can't just resize the image, but
# rather the mounted device instead
mounter = mount.Mount.instance_for_format(
imgmodel.LocalFileImage(image,
imgmodel.FORMAT_QCOW2),
None, None)
image, None, None)
if mounter.get_dev():
safe_resize2fs(mounter.device,
run_as_root=True,
finally_call=mounter.unget_dev)
else:
safe_resize2fs(image)
safe_resize2fs(image.path)
def can_resize_image(image, size):
"""Check whether we can resize the container image file."""
"""Check whether we can resize the container image file.
:param image: path to local image file
:param size: the image size in bytes
"""
LOG.debug('Checking if we can resize image %(image)s. '
'size=%(size)s', {'image': image, 'size': size})
@ -231,18 +237,18 @@ def can_resize_image(image, size):
return True
def is_image_extendable(image, use_cow=False):
def is_image_extendable(image):
"""Check whether we can extend the image."""
LOG.debug('Checking if we can extend filesystem inside %(image)s. '
'CoW=%(use_cow)s', {'image': image, 'use_cow': use_cow})
LOG.debug('Checking if we can extend filesystem inside %(image)s.',
{'image': image})
# Check the image is unpartitioned
if use_cow:
# For anything except a local raw file we must
# go via the VFS layer
if (not isinstance(image, imgmodel.LocalImage) or
image.format != imgmodel.FORMAT_RAW):
fs = None
try:
fs = vfs.VFS.instance_for_image(
imgmodel.LocalFileImage(image, imgmodel.FORMAT_QCOW2),
None)
fs = vfs.VFS.instance_for_image(image, None)
fs.setup(mount=False)
if fs.get_image_fs() in SUPPORTED_FS_TO_EXTEND:
return True
@ -263,7 +269,7 @@ def is_image_extendable(image, use_cow=False):
else:
# For raw, we can directly inspect the file system
try:
utils.execute('e2label', image)
utils.execute('e2label', image.file)
except processutils.ProcessExecutionError as e:
LOG.debug('Unable to determine label for image %(image)s with '
'error %(error)s. Cannot resize.',
@ -279,25 +285,18 @@ class _DiskImage(object):
tmp_prefix = 'openstack-disk-mount-tmp'
def __init__(self, image, partition=None, use_cow=False, mount_dir=None):
def __init__(self, image, partition=None, mount_dir=None):
"""Create a new _DiskImage object instance
:param image: the path to the disk image file
:param image: instance of nova.virt.image.model.Image
:param partition: the partition number within the image
:param use_cow: whether the disk is in qcow2 format
:param mount_dir: the directory to mount the image on
"""
# These passed to each mounter
self.partition = partition
self.mount_dir = mount_dir
if use_cow:
self.image = imgmodel.LocalFileImage(image,
imgmodel.FORMAT_QCOW2)
else:
self.image = imgmodel.LocalFileImage(image,
imgmodel.FORMAT_RAW)
self.image = image
# Internal
self._mkdir = False
@ -383,17 +382,16 @@ class _DiskImage(object):
# Public module functions
def inject_data(image, key=None, net=None, metadata=None, admin_password=None,
files=None, partition=None, use_cow=False, mandatory=()):
files=None, partition=None, mandatory=()):
"""Inject the specified items into a disk image.
:param image: the local file path
:param image: instance of nova.virt.image.model.Image
:param key: the SSH public key to inject
:param net: the network configuration to inject
:param metadata: the user metadata to inject
:param admin_password: the root password to set
:param files: the files to copy into the image
:param partition: the partition number to access
:param use_cow: whether the image is in qcow2 format
:param mandatory: the list of parameters which must not fail to inject
If an item name is not specified in the MANDATORY iterable, then a warning
@ -409,15 +407,11 @@ def inject_data(image, key=None, net=None, metadata=None, admin_password=None,
"""
LOG.debug("Inject data image=%(image)s key=%(key)s net=%(net)s "
"metadata=%(metadata)s admin_password=<SANITIZED> "
"files=%(files)s partition=%(partition)s use_cow=%(use_cow)s",
"files=%(files)s partition=%(partition)s",
{'image': image, 'key': key, 'net': net, 'metadata': metadata,
'files': files, 'partition': partition, 'use_cow': use_cow})
fmt = imgmodel.FORMAT_RAW
if use_cow:
fmt = imgmodel.FORMAT_QCOW2
'files': files, 'partition': partition})
try:
fs = vfs.VFS.instance_for_image(
imgmodel.LocalFileImage(image, fmt), partition)
fs = vfs.VFS.instance_for_image(image, partition)
fs.setup()
except Exception as e:
# If a mandatory item is passed to this function,
@ -437,15 +431,18 @@ def inject_data(image, key=None, net=None, metadata=None, admin_password=None,
fs.teardown()
def setup_container(image, container_dir, use_cow=False):
def setup_container(image, container_dir):
"""Setup the LXC container.
:param image: instance of nova.virt.image.model.Image
:param container_dir: directory to mount the image at
It will mount the loopback image to the container directory in order
to create the root filesystem for the container.
Returns path of image device which is mounted to the container directory.
"""
img = _DiskImage(image=image, use_cow=use_cow, mount_dir=container_dir)
img = _DiskImage(image=image, mount_dir=container_dir)
dev = img.mount()
if dev is None:
LOG.error(_LE("Failed to mount container filesystem '%(image)s' "

View File

@ -88,6 +88,7 @@ from nova.virt.disk.vfs import guestfs
from nova.virt import driver
from nova.virt import firewall
from nova.virt import hardware
from nova.virt.image import model as imgmodel
from nova.virt.libvirt import blockinfo
from nova.virt.libvirt import config as vconfig
from nova.virt.libvirt import dmcrypt
@ -2734,10 +2735,14 @@ class LibvirtDriver(driver.ComputeDriver):
injection_image.path, instance=instance)
return
try:
disk.inject_data(injection_image.path,
fmt = imgmodel.FORMAT_RAW
if CONF.use_cow_images:
fmt = imgmodel.FORMAT_QCOW2
image = imgmodel.LocalFileImage(injection_image.path,
fmt)
disk.inject_data(image,
key, net, metadata, admin_pass, files,
partition=target_partition,
use_cow=CONF.use_cow_images,
mandatory=('files',))
except Exception as e:
with excutils.save_and_reraise_exception():
@ -4301,9 +4306,12 @@ class LibvirtDriver(driver.ComputeDriver):
container_dir = os.path.join(inst_path, 'rootfs')
fileutils.ensure_tree(container_dir)
rootfs_dev = disk.setup_container(disk_path,
container_dir=container_dir,
use_cow=use_cow)
fmt = imgmodel.FORMAT_RAW
if use_cow:
fmt = imgmodel.FORMAT_QCOW2
image = imgmodel.LocalFileImage(disk_path, fmt)
rootfs_dev = disk.setup_container(image,
container_dir=container_dir)
try:
# Save rootfs device to disconnect it when deleting the instance
@ -6415,32 +6423,40 @@ class LibvirtDriver(driver.ComputeDriver):
'-O', 'raw', path, path_raw)
utils.execute('mv', path_raw, path)
def _disk_resize(self, info, size):
def _disk_resize(self, image, size):
"""Attempts to resize a disk to size
:param image: an instance of nova.virt.image.model.Image
Attempts to resize a disk by checking the capabilities and
preparing the format, then calling disk.api.extend.
Note: Currently only support disk extend.
"""
if not isinstance(image, imgmodel.LocalFileImage):
LOG.debug("Skipping resize of non-local image")
return
# If we have a non partitioned image that we can extend
# then ensure we're in 'raw' format so we can extend file system.
fmt, org = [info['type']] * 2
pth = info['path']
if (size and fmt == 'qcow2' and
disk.can_resize_image(pth, size) and
disk.is_image_extendable(pth, use_cow=True)):
self._disk_qcow2_to_raw(pth)
fmt = 'raw'
converted = False
if (size and
image.format == imgmodel.FORMAT_QCOW2 and
disk.can_resize_image(image.path, size) and
disk.is_image_extendable(image)):
self._disk_qcow2_to_raw(image.path)
converted = True
image = imgmodel.LocalFileImage(image.path,
imgmodel.FORMAT_RAW)
if size:
use_cow = fmt == 'qcow2'
disk.extend(pth, size, use_cow=use_cow)
disk.extend(image, size)
if fmt != org:
if converted:
# back to qcow2 (no backing_file though) so that snapshot
# will be available
self._disk_raw_to_qcow2(pth)
self._disk_raw_to_qcow2(image.path)
def finish_migration(self, context, migration, instance, disk_info,
network_info, image_meta, resize_instance,
@ -6452,7 +6468,9 @@ class LibvirtDriver(driver.ComputeDriver):
for info in disk_info:
size = self._disk_size_from_instance(instance, info)
if resize_instance:
self._disk_resize(info, size)
image = imgmodel.LocalFileImage(info['path'],
info['type'])
self._disk_resize(image, size)
if info['type'] == 'raw' and CONF.use_cow_images:
self._disk_raw_to_qcow2(info['path'])

View File

@ -35,6 +35,7 @@ from nova import keymgr
from nova.openstack.common import fileutils
from nova import utils
from nova.virt.disk import api as disk
from nova.virt.image import model as imgmodel
from nova.virt import images
from nova.virt.libvirt import config as vconfig
from nova.virt.libvirt import dmcrypt
@ -425,8 +426,9 @@ class Raw(Image):
libvirt_utils.copy_image(base, target)
if size:
# class Raw is misnamed, format may not be 'raw' in all cases
use_cow = self.driver_format == 'qcow2'
disk.extend(target, size, use_cow=use_cow)
image = imgmodel.LocalFileImage(target,
self.driver_format)
disk.extend(image, size)
generating = 'image_id' not in kwargs
if generating:
@ -473,7 +475,8 @@ class Qcow2(Image):
# This would be keyed on a 'preallocate_images' setting.
libvirt_utils.create_cow_image(base, target)
if size:
disk.extend(target, size, use_cow=True)
image = imgmodel.LocalFileImage(target, imgmodel.FORMAT_QCOW2)
disk.extend(image, size)
# Download the unmodified base image unless we already have a copy.
if not os.path.exists(base):
@ -502,7 +505,9 @@ class Qcow2(Image):
if not os.path.exists(legacy_base):
with fileutils.remove_path_on_error(legacy_base):
libvirt_utils.copy_image(base, legacy_base)
disk.extend(legacy_base, legacy_backing_size, use_cow=True)
image = imgmodel.LocalFileImage(legacy_base,
imgmodel.FORMAT_QCOW2)
disk.extend(image, legacy_backing_size)
if not os.path.exists(self.path):
with fileutils.remove_path_on_error(self.path):