Add support for partition images in agent drivers

This patch enables the partition image support for
agent drivers which support `boot` iterface.

Partial-Bug: 1526289

Co-Authored-By: Nisha Agarwal <agarwalnisha1980@gmail.com>

Depends-on: I22bc29a39bf5c35f3eecb6d4e51cebd6aee0ce1
Depends-on: I37908470484744bb720f741d378106d1cb1227a3
Change-Id: Ifc8ba098f13b6fde712a584798fceb0321137bc9
This commit is contained in:
Faizan Barmawer 2015-02-16 05:42:08 -08:00 committed by Nisha Agarwal
parent 6d1b7c6d0d
commit 644a1c36b4
11 changed files with 676 additions and 188 deletions

View File

@ -111,6 +111,11 @@ OPTIONAL_PROPERTIES = {
COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy()
COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES)
PARTITION_IMAGE_LABELS = ('kernel', 'ramdisk', 'root_gb', 'root_mb', 'swap_mb',
'ephemeral_mb', 'ephemeral_format', 'configdrive',
'preserve_ephemeral', 'image_type',
'deploy_boot_mode')
def build_instance_info_for_deploy(task):
"""Build instance_info necessary for deploying to a node.
@ -123,7 +128,7 @@ def build_instance_info_for_deploy(task):
"""
node = task.node
instance_info = node.instance_info
iwdi = node.driver_internal_info.get('is_whole_disk_image')
image_source = instance_info['image_source']
if service_utils.is_glance_image(image_source):
glance = image_service.GlanceImageService(version=2,
@ -137,6 +142,10 @@ def build_instance_info_for_deploy(task):
instance_info['image_disk_format'] = image_info['disk_format']
instance_info['image_container_format'] = (
image_info['container_format'])
if not iwdi:
instance_info['kernel'] = image_info['properties']['kernel_id']
instance_info['ramdisk'] = image_info['properties']['ramdisk_id']
else:
try:
image_service.HttpImageService().validate_href(image_source)
@ -148,6 +157,12 @@ def build_instance_info_for_deploy(task):
"is not reachable."), image_source)
instance_info['image_url'] = image_source
if not iwdi:
instance_info['image_type'] = 'partition'
i_info = deploy_utils.parse_instance_info(node)
instance_info.update(i_info)
else:
instance_info['image_type'] = 'whole-disk-image'
return instance_info
@ -256,6 +271,7 @@ class AgentDeploy(base.DeployInterface):
params['instance_info.image_source'] = image_source
error_msg = _('Node %s failed to validate deploy image info. Some '
'parameters were missing') % node.uuid
deploy_utils.check_for_missing_params(params, error_msg)
if not service_utils.is_glance_image(image_source):
@ -265,15 +281,6 @@ class AgentDeploy(base.DeployInterface):
"instance_info for node %s") % node.uuid)
check_image_size(task, image_source)
is_whole_disk_image = node.driver_internal_info.get(
'is_whole_disk_image')
# TODO(sirushtim): Remove once IPA has support for partition images.
if is_whole_disk_image is False:
raise exception.InvalidParameterValue(_(
"Node %(node)s is configured to use the %(driver)s driver "
"which currently does not support deploying partition "
"images.") % {'node': node.uuid, 'driver': node.driver})
# Validate the root device hints
deploy_utils.parse_root_device_hints(node)
@ -468,11 +475,44 @@ class AgentVendorInterface(agent_base_vendor.BaseAgentVendor):
if no_proxy is not None:
image_info['no_proxy'] = no_proxy
iwdi = node.driver_internal_info.get('is_whole_disk_image')
if not iwdi:
for label in PARTITION_IMAGE_LABELS:
image_info[label] = node.instance_info.get(label)
boot_option = deploy_utils.get_boot_option(node)
boot_mode = deploy_utils.get_boot_mode_for_deploy(node)
if boot_mode:
image_info['deploy_boot_mode'] = boot_mode
else:
image_info['deploy_boot_mode'] = 'bios'
image_info['boot_option'] = boot_option
# Tell the client to download and write the image with the given args
self._client.prepare_image(node, image_info)
task.process_event('wait')
def _get_uuid_from_result(self, task, type_uuid):
command = self._client.get_commands_status(task.node)[-1]
if command['command_result'] is not None:
words = command['command_result']['result'].split()
for word in words:
if type_uuid in word:
result = word.split('=')[1]
if not result:
msg = (_('Command result did not return %(type_uuid)s '
'for node %(node)s. The version of the IPA '
'ramdisk used in the deployment might not '
'have support for provisioning of '
'partition images.') %
{'type_uuid': type_uuid,
'node': task.node.uuid})
LOG.error(msg)
deploy_utils.set_failed_state(task, msg)
return
return result
def check_deploy_success(self, node):
# should only ever be called after we've validated that
# the prepare_image command is complete
@ -483,6 +523,7 @@ class AgentVendorInterface(agent_base_vendor.BaseAgentVendor):
def reboot_to_instance(self, task, **kwargs):
task.process_event('resume')
node = task.node
iwdi = task.node.driver_internal_info.get('is_whole_disk_image')
error = self.check_deploy_success(node)
if error is not None:
# TODO(jimrollenhagen) power off if using neutron dhcp to
@ -492,11 +533,22 @@ class AgentVendorInterface(agent_base_vendor.BaseAgentVendor):
LOG.error(msg)
deploy_utils.set_failed_state(task, msg)
return
if not iwdi:
root_uuid = self._get_uuid_from_result(task, 'root_uuid')
if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi':
efi_sys_uuid = (
self._get_uuid_from_result(task,
'efi_system_partition_uuid'))
else:
efi_sys_uuid = None
task.node.driver_internal_info['root_uuid_or_disk_id'] = root_uuid
task.node.save()
self.prepare_instance_to_boot(task, root_uuid, efi_sys_uuid)
LOG.info(_LI('Image successfully written to node %s'), node.uuid)
LOG.debug('Rebooting node %s to instance', node.uuid)
if iwdi:
manager_utils.node_set_boot_device(task, 'disk', persistent=True)
manager_utils.node_set_boot_device(task, 'disk', persistent=True)
self.reboot_and_finish_deploy(task)
# NOTE(TheJulia): If we deployed a whole disk image, we
@ -505,7 +557,7 @@ class AgentVendorInterface(agent_base_vendor.BaseAgentVendor):
# TODO(rameshg87): Not all in-tree drivers using reboot_to_instance
# have a boot interface. So include a check for now. Remove this
# check once all in-tree drivers have a boot interface.
if task.driver.boot:
if task.driver.boot and iwdi:
task.driver.boot.clean_up_ramdisk(task)

View File

@ -710,6 +710,30 @@ class BaseAgentVendor(base.VendorInterface):
task.process_event('done')
LOG.info(_LI('Deployment to node %s done'), task.node.uuid)
def prepare_instance_to_boot(self, task, root_uuid, efi_sys_uuid):
"""Prepares instance to boot.
:param task: a TaskManager object containing the node
:param root_uuid: the UUID for root partition
:param efi_sys_uuid: the UUID for the efi partition
:raises: InvalidState if fails to prepare instance
"""
node = task.node
if deploy_utils.get_boot_option(node) == "local":
# Install the boot loader
self.configure_local_boot(
task, root_uuid=root_uuid,
efi_system_part_uuid=efi_sys_uuid)
try:
task.driver.boot.prepare_instance(task)
except Exception as e:
LOG.error(_LE('Deploy failed for instance %(instance)s. '
'Error: %(error)s'),
{'instance': node.instance_uuid, 'error': e})
msg = _('Failed to continue agent deployment.')
self._log_and_raise_deployment_error(task, msg)
def configure_local_boot(self, task, root_uuid=None,
efi_system_part_uuid=None):
"""Helper method to configure local boot on the node.

View File

@ -3,3 +3,11 @@ default deploy
label deploy
kernel {{ pxe_options.deployment_aki_path }}
append initrd={{ pxe_options.deployment_ari_path }} text {{ pxe_options.pxe_append_params }} ipa-api-url={{ pxe_options['ipa-api-url'] }} ipa-driver-name={{ pxe_options['ipa-driver-name'] }}{% if pxe_options.root_device %} root_device={{ pxe_options.root_device }}{% endif %} coreos.configdrive=0
label boot_partition
kernel {{ pxe_options.aki_path }}
append initrd={{ pxe_options.ari_path }} root={{ ROOT }} ro text {{ pxe_options.pxe_append_params|default("", true) }}
label boot_whole_disk
COM32 chain.c32
append mbr:{{ DISK_IDENTIFIER }}

View File

@ -26,6 +26,7 @@ from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import excutils
from oslo_utils import strutils
import six
from six.moves.urllib import parse
@ -96,10 +97,12 @@ SUPPORTED_CAPABILITIES = {
'disk_label': ('msdos', 'gpt'),
}
DISK_LAYOUT_PARAMS = ('root_gb', 'swap_mb', 'ephemeral_gb')
# All functions are called from deploy() directly or indirectly.
# They are split for stub-out.
def discovery(portal_address, portal_port):
"""Do iSCSI discovery on portal."""
utils.execute('iscsiadm',
@ -1084,3 +1087,111 @@ def get_image_instance_info(node):
check_for_missing_params(info, error_msg)
return info
def parse_instance_info(node):
"""Gets the instance specific Node deployment info.
This method validates whether the 'instance_info' property of the
supplied node contains the required information for this driver to
deploy images to the node.
:param node: a single Node.
:returns: A dict with the instance_info values.
:raises: MissingParameterValue, if any of the required parameters are
missing.
:raises: InvalidParameterValue, if any of the parameters have invalid
value.
"""
info = node.instance_info
i_info = {}
i_info['image_source'] = info.get('image_source')
iwdi = node.driver_internal_info.get('is_whole_disk_image')
if not iwdi:
if (i_info['image_source'] and
not service_utils.is_glance_image(
i_info['image_source'])):
i_info['kernel'] = info.get('kernel')
i_info['ramdisk'] = info.get('ramdisk')
i_info['root_gb'] = info.get('root_gb')
error_msg = _("Cannot validate driver deploy. Some parameters were missing"
" in node's instance_info")
check_for_missing_params(i_info, error_msg)
# Internal use only
i_info['deploy_key'] = info.get('deploy_key')
i_info['swap_mb'] = int(info.get('swap_mb', 0))
i_info['ephemeral_gb'] = info.get('ephemeral_gb', 0)
err_msg_invalid = _("Cannot validate parameter for driver deploy. "
"Invalid parameter %(param)s. Reason: %(reason)s")
for param in DISK_LAYOUT_PARAMS:
try:
int(i_info[param])
except ValueError:
reason = _("%s is not an integer value.") % i_info[param]
raise exception.InvalidParameterValue(err_msg_invalid %
{'param': param,
'reason': reason})
i_info['root_mb'] = 1024 * int(info.get('root_gb'))
if iwdi:
if int(i_info['swap_mb']) > 0 or int(i_info['ephemeral_gb']) > 0:
err_msg_invalid = _("Cannot deploy whole disk image with "
"swap or ephemeral size set")
raise exception.InvalidParameterValue(err_msg_invalid)
i_info['ephemeral_format'] = info.get('ephemeral_format')
i_info['configdrive'] = info.get('configdrive')
if i_info['ephemeral_gb'] and not i_info['ephemeral_format']:
i_info['ephemeral_format'] = CONF.pxe.default_ephemeral_format
preserve_ephemeral = info.get('preserve_ephemeral', False)
try:
i_info['preserve_ephemeral'] = (
strutils.bool_from_string(preserve_ephemeral, strict=True))
except ValueError as e:
raise exception.InvalidParameterValue(
err_msg_invalid % {'param': 'preserve_ephemeral', 'reason': e})
# NOTE(Zhenguo): If rebuilding with preserve_ephemeral option, check
# that the disk layout is unchanged.
if i_info['preserve_ephemeral']:
_check_disk_layout_unchanged(node, i_info)
return i_info
def _check_disk_layout_unchanged(node, i_info):
"""Check whether disk layout is unchanged.
If the node has already been deployed to, this checks whether the disk
layout for the node is the same as when it had been deployed to.
:param node: the node of interest
:param i_info: instance information (a dictionary) for the node, containing
disk layout information
:raises: InvalidParameterValue if the disk layout changed
"""
# If a node has been deployed to, this is the instance information
# used for that deployment.
driver_internal_info = node.driver_internal_info
if 'instance' not in driver_internal_info:
return
error_msg = ''
for param in DISK_LAYOUT_PARAMS:
param_value = int(driver_internal_info['instance'][param])
if param_value != int(i_info[param]):
error_msg += (_(' Deployed value of %(param)s was %(param_value)s '
'but requested value is %(request_value)s.') %
{'param': param, 'param_value': param_value,
'request_value': i_info[param]})
if error_msg:
err_msg_invalid = _("The following parameters have different values "
"from previous deployment:%(error_msg)s")
raise exception.InvalidParameterValue(err_msg_invalid %
{'error_msg': error_msg})

View File

@ -20,12 +20,10 @@ from ironic_lib import utils as ironic_utils
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import fileutils
from oslo_utils import strutils
from six.moves.urllib import parse
from ironic.common import dhcp_factory
from ironic.common import exception
from ironic.common.glance_service import service_utils as glance_service_utils
from ironic.common.i18n import _
from ironic.common.i18n import _LE
from ironic.common.i18n import _LI
@ -107,39 +105,6 @@ def _get_image_file_path(node_uuid):
return os.path.join(_get_image_dir_path(node_uuid), 'disk')
def _check_disk_layout_unchanged(node, i_info):
"""Check whether disk layout is unchanged.
If the node has already been deployed to, this checks whether the disk
layout for the node is the same as when it had been deployed to.
:param node: the node of interest
:param i_info: instance information (a dictionary) for the node, containing
disk layout information
:raises: InvalidParameterValue if the disk layout changed
"""
# If a node has been deployed to, this is the instance information
# used for that deployment.
driver_internal_info = node.driver_internal_info
if 'instance' not in driver_internal_info:
return
error_msg = ''
for param in DISK_LAYOUT_PARAMS:
param_value = int(driver_internal_info['instance'][param])
if param_value != int(i_info[param]):
error_msg += (_(' Deployed value of %(param)s was %(param_value)s '
'but requested value is %(request_value)s.') %
{'param': param, 'param_value': param_value,
'request_value': i_info[param]})
if error_msg:
err_msg_invalid = _("The following parameters have different values "
"from previous deployment:%(error_msg)s")
raise exception.InvalidParameterValue(err_msg_invalid %
{'error_msg': error_msg})
def _save_disk_layout(node, i_info):
"""Saves the disk layout.
@ -159,81 +124,6 @@ def _save_disk_layout(node, i_info):
node.save()
def parse_instance_info(node):
"""Gets the instance specific Node deployment info.
This method validates whether the 'instance_info' property of the
supplied node contains the required information for this driver to
deploy images to the node.
:param node: a single Node.
:returns: A dict with the instance_info values.
:raises: MissingParameterValue, if any of the required parameters are
missing.
:raises: InvalidParameterValue, if any of the parameters have invalid
value.
"""
info = node.instance_info
i_info = {}
i_info['image_source'] = info.get('image_source')
is_whole_disk_image = node.driver_internal_info.get('is_whole_disk_image')
if not is_whole_disk_image:
if (i_info['image_source'] and
not glance_service_utils.is_glance_image(
i_info['image_source'])):
i_info['kernel'] = info.get('kernel')
i_info['ramdisk'] = info.get('ramdisk')
i_info['root_gb'] = info.get('root_gb')
error_msg = _("Cannot validate iSCSI deploy. Some parameters were missing"
" in node's instance_info")
deploy_utils.check_for_missing_params(i_info, error_msg)
# Internal use only
i_info['deploy_key'] = info.get('deploy_key')
i_info['swap_mb'] = info.get('swap_mb', 0)
i_info['ephemeral_gb'] = info.get('ephemeral_gb', 0)
err_msg_invalid = _("Cannot validate parameter for iSCSI deploy. "
"Invalid parameter %(param)s. Reason: %(reason)s")
for param in DISK_LAYOUT_PARAMS:
try:
int(i_info[param])
except ValueError:
reason = _("%s is not an integer value.") % i_info[param]
raise exception.InvalidParameterValue(err_msg_invalid %
{'param': param,
'reason': reason})
if is_whole_disk_image:
if int(i_info['swap_mb']) > 0 or int(i_info['ephemeral_gb']) > 0:
err_msg_invalid = _("Cannot deploy whole disk image with "
"swap or ephemeral size set")
raise exception.InvalidParameterValue(err_msg_invalid)
return i_info
i_info['ephemeral_format'] = info.get('ephemeral_format')
i_info['configdrive'] = info.get('configdrive')
if i_info['ephemeral_gb'] and not i_info['ephemeral_format']:
i_info['ephemeral_format'] = CONF.pxe.default_ephemeral_format
preserve_ephemeral = info.get('preserve_ephemeral', False)
try:
i_info['preserve_ephemeral'] = (
strutils.bool_from_string(preserve_ephemeral, strict=True))
except ValueError as e:
raise exception.InvalidParameterValue(
err_msg_invalid % {'param': 'preserve_ephemeral', 'reason': e})
# NOTE(Zhenguo): If rebuilding with preserve_ephemeral option, check
# that the disk layout is unchanged.
if i_info['preserve_ephemeral']:
_check_disk_layout_unchanged(node, i_info)
return i_info
def check_image_size(task):
"""Check if the requested image is larger than the root partition size.
@ -241,7 +131,7 @@ def check_image_size(task):
:raises: InstanceDeployFailure if size of the image is greater than root
partition.
"""
i_info = parse_instance_info(task.node)
i_info = deploy_utils.parse_instance_info(task.node)
image_path = _get_image_file_path(task.node.uuid)
image_mb = disk_utils.get_image_mb(image_path)
root_mb = 1024 * int(i_info['root_gb'])
@ -263,7 +153,7 @@ def cache_instance_image(ctx, node):
:returns: a tuple containing the uuid of the image and the path in
the filesystem where image is cached.
"""
i_info = parse_instance_info(node)
i_info = deploy_utils.parse_instance_info(node)
fileutils.ensure_tree(_get_image_dir_path(node.uuid))
image_path = _get_image_file_path(node.uuid)
uuid = i_info['image_source']
@ -298,7 +188,7 @@ def get_deploy_info(node, **kwargs):
value.
"""
deploy_key = kwargs.get('key')
i_info = parse_instance_info(node)
i_info = deploy_utils.parse_instance_info(node)
if i_info['deploy_key'] != deploy_key:
raise exception.InvalidParameterValue(_("Deploy key does not match"))
@ -410,7 +300,7 @@ def continue_deploy(task, **kwargs):
if params.get('preserve_ephemeral', False):
# Save disk layout information, to check that they are unchanged
# for any future rebuilds
_save_disk_layout(node, parse_instance_info(node))
_save_disk_layout(node, deploy_utils.parse_instance_info(node))
destroy_images(node.uuid)
return uuid_dict_returned
@ -562,7 +452,7 @@ def validate(task):
# Validate the root device hints
deploy_utils.parse_root_device_hints(task.node)
parse_instance_info(task.node)
deploy_utils.parse_instance_info(task.node)
def validate_pass_bootloader_info_input(task, input_params):
@ -972,21 +862,7 @@ class VendorPassthru(agent_base_vendor.BaseAgentVendor):
LOG.debug('Continuing the deployment on node %s', node.uuid)
uuid_dict_returned = do_agent_iscsi_deploy(task, self._client)
if deploy_utils.get_boot_option(node) == "local":
# Install the boot loader
root_uuid = uuid_dict_returned.get('root uuid')
efi_sys_uuid = uuid_dict_returned.get('efi system partition uuid')
self.configure_local_boot(
task, root_uuid=root_uuid,
efi_system_part_uuid=efi_sys_uuid)
try:
task.driver.boot.prepare_instance(task)
except Exception as e:
LOG.error(_LE('Deploy failed for instance %(instance)s. '
'Error: %(error)s'),
{'instance': node.instance_uuid, 'error': e})
msg = _('Failed to continue agent deployment.')
deploy_utils.set_failed_state(task, msg)
root_uuid = uuid_dict_returned.get('root uuid')
efi_sys_uuid = uuid_dict_returned.get('efi system partition uuid')
self.prepare_instance_to_boot(task, root_uuid, efi_sys_uuid)
self.reboot_and_finish_deploy(task)

View File

@ -40,6 +40,8 @@ class TestPXEUtils(db_base.DbTestCase):
u'c02d7f33c123/deploy_kernel',
'aki_path': u'/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/'
u'kernel',
'ari_path': u'/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/'
u'ramdisk',
'pxe_append_params': 'test_param',
'deployment_ari_path': u'/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7'
u'f33c123/deploy_ramdisk',
@ -50,8 +52,6 @@ class TestPXEUtils(db_base.DbTestCase):
self.pxe_options = {
'deployment_key': '0123456789ABCDEFGHIJKLMNOPQRSTUV',
'ari_path': u'/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/'
u'ramdisk',
'iscsi_target_iqn': u'iqn-1be26c0b-03f2-4d2e-ae87-c02d7f33'
u'c123',
'deployment_id': u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123',

View File

@ -3,3 +3,12 @@ default deploy
label deploy
kernel /tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/deploy_kernel
append initrd=/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/deploy_ramdisk text test_param ipa-api-url=http://192.168.122.184:6385 ipa-driver-name=agent_ipmitool root_device=vendor=fake,size=123 coreos.configdrive=0
label boot_partition
kernel /tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/kernel
append initrd=/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/ramdisk root={{ ROOT }} ro text test_param
label boot_whole_disk
COM32 chain.c32
append mbr:{{ DISK_IDENTIFIER }}

View File

@ -55,6 +55,9 @@ class TestAgentMethods(db_base.DbTestCase):
def test_build_instance_info_for_deploy_glance_image(self, glance_mock):
i_info = self.node.instance_info
i_info['image_source'] = '733d1c44-a2ea-414b-aca7-69decf20d810'
driver_internal_info = self.node.driver_internal_info
driver_internal_info['is_whole_disk_image'] = True
self.node.driver_internal_info = driver_internal_info
self.node.instance_info = i_info
self.node.save()
@ -76,14 +79,82 @@ class TestAgentMethods(db_base.DbTestCase):
glance_mock.return_value.swift_temp_url.assert_called_once_with(
image_info)
@mock.patch.object(deploy_utils, 'parse_instance_info', autospec=True)
@mock.patch.object(image_service, 'GlanceImageService', autospec=True)
def test_build_instance_info_for_deploy_glance_partition_image(
self, glance_mock, parse_instance_info_mock):
i_info = self.node.instance_info
i_info['image_source'] = '733d1c44-a2ea-414b-aca7-69decf20d810'
i_info['kernel'] = '13ce5a56-1de3-4916-b8b2-be778645d003'
i_info['ramdisk'] = 'a5a370a8-1b39-433f-be63-2c7d708e4b4e'
i_info['root_gb'] = 5
i_info['swap_mb'] = 4
i_info['ephemeral_gb'] = 0
i_info['ephemeral_format'] = None
i_info['configdrive'] = 'configdrive'
driver_internal_info = self.node.driver_internal_info
driver_internal_info['is_whole_disk_image'] = False
self.node.driver_internal_info = driver_internal_info
self.node.instance_info = i_info
self.node.save()
image_info = {'checksum': 'aa', 'disk_format': 'qcow2',
'container_format': 'bare',
'properties': {'kernel_id': 'kernel',
'ramdisk_id': 'ramdisk'}}
glance_mock.return_value.show = mock.MagicMock(spec_set=[],
return_value=image_info)
glance_obj_mock = glance_mock.return_value
glance_obj_mock.swift_temp_url.return_value = 'temp-url'
parse_instance_info_mock.return_value = {'swap_mb': 4}
image_source = '733d1c44-a2ea-414b-aca7-69decf20d810'
expected_i_info = {'root_gb': 5,
'swap_mb': 4,
'ephemeral_gb': 0,
'ephemeral_format': None,
'configdrive': 'configdrive',
'image_source': image_source,
'image_url': 'temp-url',
'kernel': 'kernel',
'ramdisk': 'ramdisk',
'image_type': 'partition',
'image_checksum': 'aa',
'fake_password': 'fakepass',
'image_container_format': 'bare',
'image_disk_format': 'qcow2',
'foo': 'bar'}
mgr_utils.mock_the_extension_manager(driver='fake_agent')
with task_manager.acquire(
self.context, self.node.uuid, shared=False) as task:
info = agent.build_instance_info_for_deploy(task)
glance_mock.assert_called_once_with(version=2,
context=task.context)
glance_mock.return_value.show.assert_called_once_with(
self.node.instance_info['image_source'])
glance_mock.return_value.swift_temp_url.assert_called_once_with(
image_info)
image_type = task.node.instance_info.get('image_type')
self.assertEqual('partition', image_type)
self.assertEqual('kernel', info.get('kernel'))
self.assertEqual('ramdisk', info.get('ramdisk'))
self.assertEqual(expected_i_info, info)
parse_instance_info_mock.assert_called_once_with(task.node)
@mock.patch.object(image_service.HttpImageService, 'validate_href',
autospec=True)
def test_build_instance_info_for_deploy_nonglance_image(
self, validate_href_mock):
i_info = self.node.instance_info
driver_internal_info = self.node.driver_internal_info
i_info['image_source'] = 'http://image-ref'
i_info['image_checksum'] = 'aa'
i_info['root_gb'] = 10
i_info['image_checksum'] = 'aa'
driver_internal_info['is_whole_disk_image'] = True
self.node.instance_info = i_info
self.node.driver_internal_info = driver_internal_info
self.node.save()
mgr_utils.mock_the_extension_manager(driver='fake_agent')
@ -97,6 +168,51 @@ class TestAgentMethods(db_base.DbTestCase):
validate_href_mock.assert_called_once_with(
mock.ANY, 'http://image-ref')
@mock.patch.object(deploy_utils, 'parse_instance_info', autospec=True)
@mock.patch.object(image_service.HttpImageService, 'validate_href',
autospec=True)
def test_build_instance_info_for_deploy_nonglance_partition_image(
self, validate_href_mock, parse_instance_info_mock):
i_info = self.node.instance_info
driver_internal_info = self.node.driver_internal_info
i_info['image_source'] = 'http://image-ref'
i_info['kernel'] = 'http://kernel-ref'
i_info['ramdisk'] = 'http://ramdisk-ref'
i_info['image_checksum'] = 'aa'
i_info['root_gb'] = 10
driver_internal_info['is_whole_disk_image'] = False
self.node.instance_info = i_info
self.node.driver_internal_info = driver_internal_info
self.node.save()
mgr_utils.mock_the_extension_manager(driver='fake_agent')
validate_href_mock.side_effect = ['http://image-ref',
'http://kernel-ref',
'http://ramdisk-ref']
parse_instance_info_mock.return_value = {'swap_mb': 5}
expected_i_info = {'image_source': 'http://image-ref',
'image_url': 'http://image-ref',
'image_type': 'partition',
'kernel': 'http://kernel-ref',
'ramdisk': 'http://ramdisk-ref',
'image_checksum': 'aa',
'root_gb': 10,
'swap_mb': 5,
'fake_password': 'fakepass',
'foo': 'bar'}
with task_manager.acquire(
self.context, self.node.uuid, shared=False) as task:
info = agent.build_instance_info_for_deploy(task)
self.assertEqual(self.node.instance_info['image_source'],
info['image_url'])
validate_href_mock.assert_called_once_with(
mock.ANY, 'http://image-ref')
self.assertEqual('partition', info.get('image_type'))
self.assertEqual(expected_i_info, info)
parse_instance_info_mock.assert_called_once_with(task.node)
@mock.patch.object(image_service.HttpImageService, 'validate_href',
autospec=True)
def test_build_instance_info_for_deploy_nonsupported_image(
@ -287,19 +403,6 @@ class TestAgentDeploy(db_base.DbTestCase):
pxe_boot_validate_mock.assert_called_once_with(
task.driver.boot, task)
@mock.patch.object(images, 'image_show', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'validate', autospec=True)
def test_validate_agent_fail_partition_image(
self, pxe_boot_validate_mock, show_mock):
with task_manager.acquire(
self.context, self.node['uuid'], shared=False) as task:
task.node.driver_internal_info['is_whole_disk_image'] = False
self.assertRaises(exception.InvalidParameterValue,
self.driver.validate, task)
pxe_boot_validate_mock.assert_called_once_with(
task.driver.boot, task)
show_mock.assert_called_once_with(self.context, 'fake-image')
@mock.patch.object(images, 'image_show', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'validate', autospec=True)
def test_validate_invalid_root_device_hints(
@ -572,20 +675,80 @@ class TestAgentVendor(db_base.DbTestCase):
}
)
def test_continue_deploy_partition_image(self):
self.node.provision_state = states.DEPLOYWAIT
self.node.target_provision_state = states.ACTIVE
i_info = self.node.instance_info
i_info['kernel'] = 'kernel'
i_info['ramdisk'] = 'ramdisk'
i_info['root_gb'] = 10
i_info['swap_mb'] = 10
i_info['ephemeral_mb'] = 0
i_info['ephemeral_format'] = 'abc'
i_info['configdrive'] = 'configdrive'
i_info['preserve_ephemeral'] = False
i_info['image_type'] = 'partition'
i_info['root_mb'] = 10240
i_info['deploy_boot_mode'] = 'bios'
i_info['capabilities'] = '{"boot_option": "local"}'
self.node.instance_info = i_info
driver_internal_info = self.node.driver_internal_info
driver_internal_info['is_whole_disk_image'] = False
self.node.driver_internal_info = driver_internal_info
self.node.save()
test_temp_url = 'http://image'
expected_image_info = {
'urls': [test_temp_url],
'id': 'fake-image',
'checksum': 'checksum',
'disk_format': 'qcow2',
'container_format': 'bare',
'stream_raw_images': True,
'kernel': 'kernel',
'ramdisk': 'ramdisk',
'root_gb': 10,
'swap_mb': 10,
'ephemeral_mb': 0,
'ephemeral_format': 'abc',
'configdrive': 'configdrive',
'preserve_ephemeral': False,
'image_type': 'partition',
'root_mb': 10240,
'boot_option': 'local',
'deploy_boot_mode': 'bios'
}
client_mock = mock.MagicMock(spec_set=['prepare_image'])
self.passthru._client = client_mock
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
self.passthru.continue_deploy(task)
client_mock.prepare_image.assert_called_with(task.node,
expected_image_info)
self.assertEqual(states.DEPLOYWAIT, task.node.provision_state)
self.assertEqual(states.ACTIVE,
task.node.target_provision_state)
@mock.patch.object(agent.AgentVendorInterface, '_get_uuid_from_result',
autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(fake.FakePower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
@mock.patch('ironic.conductor.utils.node_set_boot_device', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'prepare_instance',
autospec=True)
@mock.patch('ironic.drivers.modules.agent.AgentVendorInterface'
'.check_deploy_success', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'clean_up_ramdisk', autospec=True)
def test_reboot_to_instance(self, clean_pxe_mock, check_deploy_mock,
bootdev_mock, power_off_mock,
get_power_state_mock, node_power_action_mock):
prepare_mock, power_off_mock,
get_power_state_mock, node_power_action_mock,
uuid_mock):
check_deploy_mock.return_value = None
uuid_mock.return_value = 'root_uuid'
self.node.provision_state = states.DEPLOYWAIT
self.node.target_provision_state = states.ACTIVE
self.node.save()
@ -598,30 +761,83 @@ class TestAgentVendor(db_base.DbTestCase):
clean_pxe_mock.assert_called_once_with(task.driver.boot, task)
check_deploy_mock.assert_called_once_with(mock.ANY, task.node)
bootdev_mock.assert_called_once_with(task, 'disk', persistent=True)
power_off_mock.assert_called_once_with(task.node)
get_power_state_mock.assert_called_once_with(task)
node_power_action_mock.assert_called_once_with(
task, states.REBOOT)
self.assertFalse(prepare_mock.called)
self.assertEqual(states.ACTIVE, task.node.provision_state)
self.assertEqual(states.NOSTATE, task.node.target_provision_state)
driver_int_info = task.node.driver_internal_info
self.assertIsNone(driver_int_info.get('root_uuid_or_disk_id'))
self.assertFalse(uuid_mock.called)
@mock.patch.object(deploy_utils, 'get_boot_mode_for_deploy', autospec=True)
@mock.patch.object(agent.AgentVendorInterface, '_get_uuid_from_result',
autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(fake.FakePower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
@mock.patch('ironic.conductor.utils.node_set_boot_device', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'prepare_instance',
autospec=True)
@mock.patch('ironic.drivers.modules.agent.AgentVendorInterface'
'.check_deploy_success', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'clean_up_ramdisk', autospec=True)
def test_reboot_to_instance_partition_image(self, clean_pxe_mock,
check_deploy_mock,
prepare_mock, power_off_mock,
get_power_state_mock,
node_power_action_mock,
uuid_mock, boot_mode_mock):
check_deploy_mock.return_value = None
uuid_mock.return_value = 'root_uuid'
self.node.provision_state = states.DEPLOYWAIT
self.node.target_provision_state = states.ACTIVE
self.node.save()
boot_mode_mock.return_value = 'bios'
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
get_power_state_mock.return_value = states.POWER_OFF
task.node.driver_internal_info['is_whole_disk_image'] = False
self.passthru.reboot_to_instance(task)
self.assertFalse(clean_pxe_mock.called)
check_deploy_mock.assert_called_once_with(mock.ANY, task.node)
power_off_mock.assert_called_once_with(task.node)
get_power_state_mock.assert_called_once_with(task)
node_power_action_mock.assert_called_once_with(
task, states.REBOOT)
prepare_mock.assert_called_once_with(task.driver.boot, task)
self.assertEqual(states.ACTIVE, task.node.provision_state)
self.assertEqual(states.NOSTATE, task.node.target_provision_state)
driver_int_info = task.node.driver_internal_info
self.assertEqual(driver_int_info.get('root_uuid_or_disk_id'),
'root_uuid')
uuid_mock.assert_called_once_with(self.passthru, task, 'root_uuid')
boot_mode_mock.assert_called_once_with(task.node)
@mock.patch.object(agent.AgentVendorInterface, '_get_uuid_from_result',
autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(fake.FakePower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
@mock.patch.object(pxe.PXEBoot, 'prepare_instance',
autospec=True)
@mock.patch('ironic.drivers.modules.agent.AgentVendorInterface'
'.check_deploy_success', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'clean_up_ramdisk', autospec=True)
def test_reboot_to_instance_boot_none(self, clean_pxe_mock,
check_deploy_mock,
bootdev_mock, power_off_mock,
prepare_mock, power_off_mock,
get_power_state_mock,
node_power_action_mock):
node_power_action_mock,
uuid_mock):
check_deploy_mock.return_value = None
self.node.provision_state = states.DEPLOYWAIT
self.node.target_provision_state = states.ACTIVE
self.node.save()
@ -634,8 +850,96 @@ class TestAgentVendor(db_base.DbTestCase):
self.passthru.reboot_to_instance(task)
self.assertFalse(clean_pxe_mock.called)
self.assertFalse(prepare_mock.called)
power_off_mock.assert_called_once_with(task.node)
check_deploy_mock.assert_called_once_with(mock.ANY, task.node)
bootdev_mock.assert_called_once_with(task, 'disk', persistent=True)
driver_int_info = task.node.driver_internal_info
self.assertIsNone(driver_int_info.get('root_uuid_or_disk_id'))
get_power_state_mock.assert_called_once_with(task)
node_power_action_mock.assert_called_once_with(
task, states.REBOOT)
self.assertEqual(states.ACTIVE, task.node.provision_state)
self.assertEqual(states.NOSTATE, task.node.target_provision_state)
self.assertFalse(uuid_mock.called)
@mock.patch.object(agent.AgentVendorInterface, '_get_uuid_from_result',
autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(fake.FakePower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
@mock.patch.object(pxe.PXEBoot, 'prepare_instance',
autospec=True)
@mock.patch('ironic.drivers.modules.agent.AgentVendorInterface'
'.check_deploy_success', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'clean_up_ramdisk', autospec=True)
def test_reboot_to_instance_boot_error(self, clean_pxe_mock,
check_deploy_mock,
prepare_mock, power_off_mock,
get_power_state_mock,
node_power_action_mock,
uuid_mock):
check_deploy_mock.return_value = "Error"
uuid_mock.return_value = None
self.node.provision_state = states.DEPLOYWAIT
self.node.target_provision_state = states.ACTIVE
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
get_power_state_mock.return_value = states.POWER_OFF
task.node.driver_internal_info['is_whole_disk_image'] = True
task.driver.boot = None
self.passthru.reboot_to_instance(task)
self.assertFalse(clean_pxe_mock.called)
self.assertFalse(prepare_mock.called)
self.assertFalse(power_off_mock.called)
check_deploy_mock.assert_called_once_with(mock.ANY, task.node)
self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
'configure_local_boot', autospec=True)
@mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True)
@mock.patch.object(agent.AgentVendorInterface, '_get_uuid_from_result',
autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(fake.FakePower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
@mock.patch.object(pxe.PXEBoot, 'prepare_instance',
autospec=True)
@mock.patch('ironic.drivers.modules.agent.AgentVendorInterface'
'.check_deploy_success', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'clean_up_ramdisk', autospec=True)
def test_reboot_to_instance_localboot(self, clean_pxe_mock,
check_deploy_mock,
prepare_mock, power_off_mock,
get_power_state_mock,
node_power_action_mock,
uuid_mock,
bootdev_mock,
configure_mock):
check_deploy_mock.return_value = None
uuid_mock.side_effect = ['root_uuid', 'efi_uuid']
self.node.provision_state = states.DEPLOYWAIT
self.node.target_provision_state = states.ACTIVE
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
get_power_state_mock.return_value = states.POWER_OFF
task.node.driver_internal_info['is_whole_disk_image'] = False
boot_option = {'capabilities': '{"boot_option": "local"}'}
task.node.instance_info = boot_option
self.passthru.reboot_to_instance(task)
self.assertFalse(clean_pxe_mock.called)
check_deploy_mock.assert_called_once_with(mock.ANY, task.node)
self.assertFalse(bootdev_mock.called)
power_off_mock.assert_called_once_with(task.node)
get_power_state_mock.assert_called_once_with(task)
node_power_action_mock.assert_called_once_with(

View File

@ -29,6 +29,7 @@ from ironic.drivers.modules import agent_base_vendor
from ironic.drivers.modules import agent_client
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules import fake
from ironic.drivers.modules import pxe
from ironic import objects
from ironic.tests.unit.conductor import mgr_utils
from ironic.tests.unit.db import base as db_base
@ -791,6 +792,93 @@ class TestBaseAgentVendor(db_base.DbTestCase):
self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
@mock.patch.object(deploy_utils, 'set_failed_state', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'prepare_instance', autospec=True)
@mock.patch.object(deploy_utils, 'get_boot_option', autospec=True)
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
'configure_local_boot', autospec=True)
def test_prepare_instance_to_boot_netboot(self, configure_mock,
boot_option_mock,
prepare_instance_mock,
failed_state_mock):
boot_option_mock.return_value = 'netboot'
prepare_instance_mock.return_value = None
self.node.provision_state = states.DEPLOYING
self.node.target_provision_state = states.ACTIVE
self.node.save()
root_uuid = 'root_uuid'
efi_system_part_uuid = 'efi_sys_uuid'
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
self.passthru.prepare_instance_to_boot(task, root_uuid,
efi_system_part_uuid)
self.assertFalse(configure_mock.called)
boot_option_mock.assert_called_once_with(task.node)
prepare_instance_mock.assert_called_once_with(task.driver.boot,
task)
self.assertFalse(failed_state_mock.called)
@mock.patch.object(deploy_utils, 'set_failed_state', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'prepare_instance', autospec=True)
@mock.patch.object(deploy_utils, 'get_boot_option', autospec=True)
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
'configure_local_boot', autospec=True)
def test_prepare_instance_to_boot_localboot(self, configure_mock,
boot_option_mock,
prepare_instance_mock,
failed_state_mock):
boot_option_mock.return_value = 'local'
prepare_instance_mock.return_value = None
self.node.provision_state = states.DEPLOYING
self.node.target_provision_state = states.ACTIVE
self.node.save()
root_uuid = 'root_uuid'
efi_system_part_uuid = 'efi_sys_uuid'
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
self.passthru.prepare_instance_to_boot(task, root_uuid,
efi_system_part_uuid)
configure_mock.assert_called_once_with(self.passthru, task,
root_uuid,
efi_system_part_uuid)
boot_option_mock.assert_called_once_with(task.node)
prepare_instance_mock.assert_called_once_with(task.driver.boot,
task)
self.assertFalse(failed_state_mock.called)
@mock.patch.object(deploy_utils, 'set_failed_state', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'prepare_instance', autospec=True)
@mock.patch.object(deploy_utils, 'get_boot_option', autospec=True)
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
'configure_local_boot', autospec=True)
def test_prepare_instance_to_boot_configure_fails(self, configure_mock,
boot_option_mock,
prepare_mock,
failed_state_mock):
boot_option_mock.return_value = 'local'
self.node.provision_state = states.DEPLOYING
self.node.target_provision_state = states.ACTIVE
self.node.save()
root_uuid = 'root_uuid'
efi_system_part_uuid = 'efi_sys_uuid'
reason = 'reason'
configure_mock.side_effect = (
exception.InstanceDeployFailure(reason=reason))
prepare_mock.side_effect = (
exception.InstanceDeployFailure(reason=reason))
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
self.assertRaises(exception.InstanceDeployFailure,
self.passthru.prepare_instance_to_boot, task,
root_uuid, efi_system_part_uuid)
configure_mock.assert_called_once_with(self.passthru, task,
root_uuid,
efi_system_part_uuid)
boot_option_mock.assert_called_once_with(task.node)
self.assertFalse(prepare_mock.called)
self.assertFalse(failed_state_mock.called)
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
'notify_conductor_resume_clean', autospec=True)
@mock.patch.object(agent_client.AgentClient, 'get_commands_status',

View File

@ -61,7 +61,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
instance_info=INST_INFO_DICT,
driver_internal_info=DRV_INTERNAL_INFO_DICT
)
info = iscsi_deploy.parse_instance_info(node)
info = deploy_utils.parse_instance_info(node)
self.assertIsNotNone(info.get('image_source'))
self.assertIsNotNone(info.get('root_gb'))
self.assertEqual(0, info.get('ephemeral_gb'))
@ -76,7 +76,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
self.assertRaises(exception.MissingParameterValue,
iscsi_deploy.parse_instance_info,
deploy_utils.parse_instance_info,
node)
def test_parse_instance_info_missing_root_gb(self):
@ -89,7 +89,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
self.assertRaises(exception.MissingParameterValue,
iscsi_deploy.parse_instance_info,
deploy_utils.parse_instance_info,
node)
def test_parse_instance_info_invalid_root_gb(self):
@ -100,7 +100,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
self.assertRaises(exception.InvalidParameterValue,
iscsi_deploy.parse_instance_info,
deploy_utils.parse_instance_info,
node)
def test_parse_instance_info_valid_ephemeral_gb(self):
@ -113,10 +113,22 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
self.context, instance_info=info,
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
data = iscsi_deploy.parse_instance_info(node)
data = deploy_utils.parse_instance_info(node)
self.assertEqual(ephemeral_gb, data.get('ephemeral_gb'))
self.assertEqual(ephemeral_fmt, data.get('ephemeral_format'))
def test_parse_instance_info_unicode_swap_mb(self):
swap_mb = u'10'
swap_mb_int = 10
info = dict(INST_INFO_DICT)
info['swap_mb'] = swap_mb
node = obj_utils.create_test_node(
self.context, instance_info=info,
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
data = deploy_utils.parse_instance_info(node)
self.assertEqual(swap_mb_int, data.get('swap_mb'))
def test_parse_instance_info_invalid_ephemeral_gb(self):
info = dict(INST_INFO_DICT)
info['ephemeral_gb'] = 'foobar'
@ -127,7 +139,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
self.assertRaises(exception.InvalidParameterValue,
iscsi_deploy.parse_instance_info,
deploy_utils.parse_instance_info,
node)
def test_parse_instance_info_valid_ephemeral_missing_format(self):
@ -141,7 +153,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
self.context, instance_info=info,
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
instance_info = iscsi_deploy.parse_instance_info(node)
instance_info = deploy_utils.parse_instance_info(node)
self.assertEqual(ephemeral_fmt, instance_info['ephemeral_format'])
def test_parse_instance_info_valid_preserve_ephemeral_true(self):
@ -155,7 +167,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
instance_info=info,
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
data = iscsi_deploy.parse_instance_info(node)
data = deploy_utils.parse_instance_info(node)
self.assertTrue(data.get('preserve_ephemeral'))
def test_parse_instance_info_valid_preserve_ephemeral_false(self):
@ -168,7 +180,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
instance_info=info,
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
data = iscsi_deploy.parse_instance_info(node)
data = deploy_utils.parse_instance_info(node)
self.assertFalse(data.get('preserve_ephemeral'))
def test_parse_instance_info_invalid_preserve_ephemeral(self):
@ -179,7 +191,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
self.assertRaises(exception.InvalidParameterValue,
iscsi_deploy.parse_instance_info,
deploy_utils.parse_instance_info,
node)
def test_parse_instance_info_invalid_ephemeral_disk(self):
@ -197,7 +209,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
driver_internal_info=drv_internal_dict,
)
self.assertRaises(exception.InvalidParameterValue,
iscsi_deploy.parse_instance_info,
deploy_utils.parse_instance_info,
node)
def test__check_disk_layout_unchanged_fails(self):
@ -215,7 +227,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
driver_internal_info=drv_internal_dict,
)
self.assertRaises(exception.InvalidParameterValue,
iscsi_deploy._check_disk_layout_unchanged,
deploy_utils._check_disk_layout_unchanged,
node, info)
def test__check_disk_layout_unchanged(self):
@ -232,7 +244,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
self.context, instance_info=info,
driver_internal_info=drv_internal_dict,
)
self.assertIsNone(iscsi_deploy._check_disk_layout_unchanged(node,
self.assertIsNone(deploy_utils._check_disk_layout_unchanged(node,
info))
def test__save_disk_layout(self):
@ -259,7 +271,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
self.context, instance_info=info,
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
instance_info = iscsi_deploy.parse_instance_info(node)
instance_info = deploy_utils.parse_instance_info(node)
self.assertEqual('http://1.2.3.4/cd', instance_info['configdrive'])
def test_parse_instance_info_nonglance_image(self):
@ -271,7 +283,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
self.context, instance_info=info,
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
iscsi_deploy.parse_instance_info(node)
deploy_utils.parse_instance_info(node)
def test_parse_instance_info_nonglance_image_no_kernel(self):
info = INST_INFO_DICT.copy()
@ -282,7 +294,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
driver_internal_info=DRV_INTERNAL_INFO_DICT,
)
self.assertRaises(exception.MissingParameterValue,
iscsi_deploy.parse_instance_info, node)
deploy_utils.parse_instance_info, node)
def test_parse_instance_info_whole_disk_image(self):
driver_internal_info = dict(DRV_INTERNAL_INFO_DICT)
@ -291,7 +303,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
self.context, instance_info=INST_INFO_DICT,
driver_internal_info=driver_internal_info,
)
instance_info = iscsi_deploy.parse_instance_info(node)
instance_info = deploy_utils.parse_instance_info(node)
self.assertIsNotNone(instance_info.get('image_source'))
self.assertIsNotNone(instance_info.get('root_gb'))
self.assertEqual(0, instance_info.get('swap_mb'))
@ -303,7 +315,7 @@ class IscsiDeployValidateParametersTestCase(db_base.DbTestCase):
del info['root_gb']
node = obj_utils.create_test_node(self.context, instance_info=info)
self.assertRaises(exception.InvalidParameterValue,
iscsi_deploy.parse_instance_info, node)
deploy_utils.parse_instance_info, node)
class IscsiDeployPrivateMethodsTestCase(db_base.DbTestCase):

View File

@ -0,0 +1,4 @@
---
features:
- Adds support for partition images for agent
based drivers.