Accepts option for conv flags in dd command
When using dd command, it may be needed to specify conversion options, such as sparse for optimization. This change allows to accept this option, in preparation for ironic to sent it when enabled on configuration. Change-Id: I166abbf513557a836de3cce4fc9ea6b7fedbb562 Story: #2003755 Task: #26443
This commit is contained in:
parent
3234f432e8
commit
217edfeca5
|
@ -313,9 +313,15 @@ def is_block_device(dev):
|
|||
raise exception.InstanceDeployFailure(msg)
|
||||
|
||||
|
||||
def dd(src, dst):
|
||||
def dd(src, dst, conv_flags=None):
|
||||
"""Execute dd from src to dst."""
|
||||
utils.dd(src, dst, 'bs=%s' % CONF.disk_utils.dd_block_size, 'oflag=direct')
|
||||
if conv_flags:
|
||||
extra_args = ['conv=%s' % conv_flags]
|
||||
else:
|
||||
extra_args = []
|
||||
|
||||
utils.dd(src, dst, 'bs=%s' % CONF.disk_utils.dd_block_size, 'oflag=direct',
|
||||
*extra_args)
|
||||
|
||||
|
||||
def qemu_img_info(path):
|
||||
|
@ -335,10 +341,10 @@ def convert_image(source, dest, out_format, run_as_root=False):
|
|||
utils.execute(*cmd, run_as_root=run_as_root, prlimit=QEMU_IMG_LIMITS)
|
||||
|
||||
|
||||
def populate_image(src, dst):
|
||||
def populate_image(src, dst, conv_flags=None):
|
||||
data = qemu_img_info(src)
|
||||
if data.file_format == 'raw':
|
||||
dd(src, dst)
|
||||
dd(src, dst, conv_flags=conv_flags)
|
||||
else:
|
||||
convert_image(src, dst, 'raw', True)
|
||||
|
||||
|
@ -485,7 +491,7 @@ def _get_configdrive(configdrive, node_uuid, tempdir=None):
|
|||
def work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, ephemeral_format,
|
||||
image_path, node_uuid, preserve_ephemeral=False,
|
||||
configdrive=None, boot_option="netboot", boot_mode="bios",
|
||||
tempdir=None, disk_label=None, cpu_arch=""):
|
||||
tempdir=None, disk_label=None, cpu_arch="", conv_flags=None):
|
||||
"""Create partitions and copy an image to the root partition.
|
||||
|
||||
:param dev: Path for the device to work on.
|
||||
|
@ -513,6 +519,9 @@ def work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, ephemeral_format,
|
|||
steps will be taken. This default should be used for x86_64. When
|
||||
set to ppc64*, architecture specific steps are taken for booting a
|
||||
partition image locally.
|
||||
:param conv_flags: Flags that need to be sent to the dd command, to control
|
||||
the conversion of the original file when copying to the host. It can
|
||||
contain several options separated by commas.
|
||||
:returns: a dictionary containing the following keys:
|
||||
'root uuid': UUID of root partition
|
||||
'efi system partition uuid': UUID of the uefi system partition
|
||||
|
@ -575,7 +584,7 @@ def work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, ephemeral_format,
|
|||
|
||||
if configdrive_part:
|
||||
# Copy the configdrive content to the configdrive partition
|
||||
dd(configdrive_file, configdrive_part)
|
||||
dd(configdrive_file, configdrive_part, conv_flags=conv_flags)
|
||||
LOG.info("Configdrive for node %(node)s successfully copied "
|
||||
"onto partition %(partition)s",
|
||||
{'node': node_uuid, 'partition': configdrive_part})
|
||||
|
@ -586,7 +595,7 @@ def work_on_disk(dev, root_mb, swap_mb, ephemeral_mb, ephemeral_format,
|
|||
if configdrive_file:
|
||||
utils.unlink_without_raise(configdrive_file)
|
||||
|
||||
populate_image(image_path, root_part)
|
||||
populate_image(image_path, root_part, conv_flags=conv_flags)
|
||||
LOG.info("Image for %(node)s successfully populated",
|
||||
{'node': node_uuid})
|
||||
|
||||
|
|
|
@ -202,7 +202,8 @@ class WorkOnDiskTestCase(base.IronicLibTestCase):
|
|||
|
||||
@mock.patch.object(utils, 'mkfs', lambda fs, path, label=None: None)
|
||||
@mock.patch.object(disk_utils, 'block_uuid', lambda p: 'uuid')
|
||||
@mock.patch.object(disk_utils, 'populate_image', lambda *_: None)
|
||||
@mock.patch.object(disk_utils, 'populate_image', lambda image_path,
|
||||
root_path, conv_flags=None: None)
|
||||
def test_gpt_disk_label(self):
|
||||
ephemeral_part = '/dev/fake-part1'
|
||||
swap_part = '/dev/fake-part2'
|
||||
|
@ -220,7 +221,7 @@ class WorkOnDiskTestCase(base.IronicLibTestCase):
|
|||
disk_utils.work_on_disk(self.dev, self.root_mb,
|
||||
self.swap_mb, ephemeral_mb, ephemeral_format,
|
||||
self.image_path, self.node_uuid,
|
||||
disk_label='gpt')
|
||||
disk_label='gpt', conv_flags=None)
|
||||
self.assertEqual(self.mock_ibd.call_args_list, calls)
|
||||
self.mock_mp.assert_called_once_with(self.dev, self.root_mb,
|
||||
self.swap_mb, ephemeral_mb,
|
||||
|
@ -263,7 +264,7 @@ class WorkOnDiskTestCase(base.IronicLibTestCase):
|
|||
mock_mkfs.assert_called_once_with(fs='vfat', path=efi_part,
|
||||
label='efi-part')
|
||||
mock_populate_image.assert_called_once_with(self.image_path,
|
||||
root_part)
|
||||
root_part, conv_flags=None)
|
||||
mock_block_uuid.assert_any_call(root_part)
|
||||
mock_block_uuid.assert_any_call(efi_part)
|
||||
|
||||
|
@ -309,7 +310,7 @@ class WorkOnDiskTestCase(base.IronicLibTestCase):
|
|||
|
||||
self.mock_mp.return_value = {'PReP Boot partition': prep_part,
|
||||
'root': root_part}
|
||||
self.mock_ibd.return_value = True
|
||||
self.mock_ibd.return_vaue = True
|
||||
calls = [mock.call(root_part),
|
||||
mock.call(prep_part)]
|
||||
disk_utils.work_on_disk(self.dev, self.root_mb,
|
||||
|
@ -328,6 +329,30 @@ class WorkOnDiskTestCase(base.IronicLibTestCase):
|
|||
cpu_arch="ppc64le")
|
||||
self.assertFalse(mock_mkfs.called)
|
||||
|
||||
@mock.patch.object(disk_utils, 'block_uuid', autospec=True)
|
||||
@mock.patch.object(disk_utils, 'populate_image', autospec=True)
|
||||
@mock.patch.object(utils, 'mkfs', autospec=True)
|
||||
def test_convert_to_sparse(self, mock_mkfs, mock_populate_image,
|
||||
mock_block_uuid):
|
||||
ephemeral_part = '/dev/fake-part1'
|
||||
swap_part = '/dev/fake-part2'
|
||||
root_part = '/dev/fake-part3'
|
||||
ephemeral_mb = 256
|
||||
ephemeral_format = 'exttest'
|
||||
|
||||
self.mock_mp.return_value = {'ephemeral': ephemeral_part,
|
||||
'swap': swap_part,
|
||||
'root': root_part}
|
||||
self.mock_ibd.return_value = True
|
||||
disk_utils.work_on_disk(self.dev, self.root_mb,
|
||||
self.swap_mb, ephemeral_mb, ephemeral_format,
|
||||
self.image_path, self.node_uuid,
|
||||
disk_label='gpt', conv_flags='sparse')
|
||||
|
||||
mock_populate_image.assert_called_once_with(self.image_path,
|
||||
root_part,
|
||||
conv_flags='sparse')
|
||||
|
||||
|
||||
@mock.patch.object(utils, 'execute', autospec=True)
|
||||
class MakePartitionsTestCase(base.IronicLibTestCase):
|
||||
|
@ -612,7 +637,15 @@ class PopulateImageTestCase(base.IronicLibTestCase):
|
|||
type(mock_qinfo.return_value).file_format = mock.PropertyMock(
|
||||
return_value='raw')
|
||||
disk_utils.populate_image('src', 'dst')
|
||||
mock_dd.assert_called_once_with('src', 'dst')
|
||||
mock_dd.assert_called_once_with('src', 'dst', conv_flags=None)
|
||||
self.assertFalse(mock_cg.called)
|
||||
|
||||
def test_populate_raw_image_with_convert(self, mock_cg, mock_qinfo,
|
||||
mock_dd):
|
||||
type(mock_qinfo.return_value).file_format = mock.PropertyMock(
|
||||
return_value='raw')
|
||||
disk_utils.populate_image('src', 'dst', conv_flags='sparse')
|
||||
mock_dd.assert_called_once_with('src', 'dst', conv_flags='sparse')
|
||||
self.assertFalse(mock_cg.called)
|
||||
|
||||
def test_populate_qcow2_image(self, mock_cg, mock_qinfo, mock_dd):
|
||||
|
|
Loading…
Reference in New Issue