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:
parent
d81f6eb4d3
commit
5453d4b7a1
|
@ -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]
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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' "
|
||||
|
|
|
@ -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'])
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue