Support configdrive in iscsi deploy for whole disk images

This will work for UEFI only or BIOS only images. It will not
work for hybrid images; which are capable of boot from BIOS
and UEFI boot mode.

Partial-Bug: #1493328

Change-Id: I9a0775a147d5bac711b58b4b6cf0135ec68509f7
This commit is contained in:
Shivanand Tendulker 2015-09-18 04:43:35 -07:00
parent 53f8b173ae
commit 1027c1bc44
7 changed files with 80 additions and 6 deletions

View File

@ -258,6 +258,7 @@ class AgentDeployMixin(agent_base_vendor.AgentDeployMixin):
if no_proxy is not None:
image_info['no_proxy'] = no_proxy
image_info['node_uuid'] = node.uuid
iwdi = node.driver_internal_info.get('is_whole_disk_image')
if not iwdi:
for label in PARTITION_IMAGE_LABELS:
@ -272,7 +273,6 @@ class AgentDeployMixin(agent_base_vendor.AgentDeployMixin):
disk_label = deploy_utils.get_disk_label(node)
if disk_label is not None:
image_info['disk_label'] = disk_label
image_info['node_uuid'] = node.uuid
# Tell the client to download and write the image with the given args
self._client.prepare_image(node, image_info)

View File

@ -363,7 +363,7 @@ def deploy_partition_image(
def deploy_disk_image(address, port, iqn, lun,
image_path, node_uuid):
image_path, node_uuid, configdrive=None):
"""All-in-one function to deploy a whole disk image to a node.
:param address: The iSCSI IP address.
@ -373,6 +373,8 @@ def deploy_disk_image(address, port, iqn, lun,
:param image_path: Path for the instance's disk image.
:param node_uuid: node's uuid. Used for logging. Currently not in use
by this function but could be used in the future.
:param configdrive: Optional. Base64 encoded Gzipped configdrive content
or configdrive HTTP URL.
:returns: a dictionary containing the key 'disk identifier' to identify
the disk which was used for deployment.
"""
@ -381,6 +383,10 @@ def deploy_disk_image(address, port, iqn, lun,
disk_utils.populate_image(image_path, dev)
disk_identifier = disk_utils.get_disk_identifier(dev)
if configdrive:
disk_utils.create_config_drive_partition(node_uuid, dev,
configdrive)
return {'disk identifier': disk_identifier}
@ -1181,6 +1187,7 @@ def parse_instance_info(node):
# ensuring that it is possible
i_info['swap_mb'] = info.get('swap_mb', 0)
i_info['ephemeral_gb'] = info.get('ephemeral_gb', 0)
i_info['configdrive'] = info.get('configdrive')
err_msg_invalid = _("Cannot validate parameter for driver deploy. "
"Invalid parameter %(param)s. Reason: %(reason)s")
for param in DISK_LAYOUT_PARAMS:

View File

@ -183,12 +183,13 @@ def get_deploy_info(node, address, iqn, port=None, lun='1'):
_("Parameters %s were not passed to ironic"
" for deploy.") % missing)
# configdrive is nullable
params['configdrive'] = i_info.get('configdrive')
if is_whole_disk_image:
return params
# configdrive and ephemeral_format are nullable
# ephemeral_format is nullable
params['ephemeral_format'] = i_info.get('ephemeral_format')
params['configdrive'] = i_info.get('configdrive')
return params

View File

@ -662,6 +662,7 @@ class TestAgentVendor(db_base.DbTestCase):
expected_image_info = {
'urls': [test_temp_url],
'id': 'fake-image',
'node_uuid': self.node.uuid,
'checksum': 'checksum',
'disk_format': 'qcow2',
'container_format': 'bare',

View File

@ -874,8 +874,10 @@ class PhysicalWorkTestCase(tests_base.TestCase):
self.assertEqual(root_uuid, uuid_dict_returned['root uuid'])
mock_unlink.assert_called_once_with('configdrive-path')
@mock.patch.object(disk_utils, 'create_config_drive_partition',
autospec=True)
@mock.patch.object(disk_utils, 'get_disk_identifier', autospec=True)
def test_deploy_whole_disk_image(self, mock_gdi):
def test_deploy_whole_disk_image(self, mock_gdi, create_config_drive_mock):
"""Check loosely all functions are called with right args."""
address = '127.0.0.1'
port = 3306
@ -904,10 +906,55 @@ class PhysicalWorkTestCase(tests_base.TestCase):
mock.call.populate_image(image_path, dev)]
uuid_dict_returned = utils.deploy_disk_image(address, port, iqn, lun,
image_path, node_uuid)
image_path, node_uuid,
configdrive=None)
self.assertEqual(utils_calls_expected, utils_mock.mock_calls)
self.assertEqual(disk_utils_calls_expected, disk_utils_mock.mock_calls)
self.assertFalse(create_config_drive_mock.called)
self.assertEqual('0x12345678', uuid_dict_returned['disk identifier'])
@mock.patch.object(disk_utils, 'create_config_drive_partition',
autospec=True)
@mock.patch.object(disk_utils, 'get_disk_identifier', autospec=True)
def test_deploy_whole_disk_image_with_config_drive(self, mock_gdi,
create_partition_mock):
"""Check loosely all functions are called with right args."""
address = '127.0.0.1'
port = 3306
iqn = 'iqn.xyz'
lun = 1
image_path = '/tmp/xyz/image'
node_uuid = "12345678-1234-1234-1234-1234567890abcxyz"
config_url = 'http://1.2.3.4/cd'
dev = '/dev/fake'
utils_list = ['get_dev', 'discovery', 'login_iscsi', 'logout_iscsi',
'delete_iscsi']
disk_utils_list = ['is_block_device', 'populate_image']
utils_mock = self._mock_calls(utils_list, utils)
disk_utils_mock = self._mock_calls(disk_utils_list, disk_utils)
utils_mock.get_dev.return_value = dev
disk_utils_mock.is_block_device.return_value = True
mock_gdi.return_value = '0x12345678'
utils_calls_expected = [mock.call.get_dev(address, port, iqn, lun),
mock.call.discovery(address, port),
mock.call.login_iscsi(address, port, iqn),
mock.call.logout_iscsi(address, port, iqn),
mock.call.delete_iscsi(address, port, iqn)]
disk_utils_calls_expected = [mock.call.is_block_device(dev),
mock.call.populate_image(image_path, dev)]
uuid_dict_returned = utils.deploy_disk_image(address, port, iqn, lun,
image_path, node_uuid,
configdrive=config_url)
utils_mock.assert_has_calls(utils_calls_expected)
disk_utils_mock.assert_has_calls(disk_utils_calls_expected)
create_partition_mock.assert_called_once_with(node_uuid, dev,
config_url)
self.assertEqual('0x12345678', uuid_dict_returned['disk identifier'])
@mock.patch.object(common_utils, 'execute', autospec=True)

View File

@ -386,6 +386,17 @@ class IscsiDeployMethodsTestCase(db_base.DbTestCase):
ret_val = self._test_get_deploy_info()
self.assertEqual(3266, ret_val['port'])
def test_get_deploy_info_whole_disk_image(self):
instance_info = self.node.instance_info
instance_info['configdrive'] = 'My configdrive'
self.node.instance_info = instance_info
self.node.driver_internal_info['is_whole_disk_image'] = True
kwargs = {'address': '1.1.1.1', 'iqn': 'target-iqn'}
ret_val = iscsi_deploy.get_deploy_info(self.node, **kwargs)
self.assertEqual('1.1.1.1', ret_val['address'])
self.assertEqual('target-iqn', ret_val['iqn'])
self.assertEqual('My configdrive', ret_val['configdrive'])
@mock.patch.object(iscsi_deploy, 'continue_deploy', autospec=True)
def test_do_agent_iscsi_deploy_okay(self, continue_deploy_mock):
agent_client_mock = mock.MagicMock(spec_set=agent_client.AgentClient)

View File

@ -0,0 +1,7 @@
---
features:
- Added configdrive support for whole disk images
for iSCSI based deploy.
This will work for UEFI only or BIOS only images.
It will not work for hybrid images which are
capable of booting from BIOS and UEFI boot mode.